about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-04 06:41:27 +0000
committerbors <bors@rust-lang.org>2023-04-04 06:41:27 +0000
commit35d06f9c747bc791d7d6902248d851da98616a57 (patch)
treed02005fb381f0214efa68971b1a759920cfaf21b
parentbd991d9953625e9d51fc4fcb5e19aa9c3ea598a8 (diff)
parent000e94e67d2b439c9dc3644c124ae4c405624a14 (diff)
downloadrust-35d06f9c747bc791d7d6902248d851da98616a57.tar.gz
rust-35d06f9c747bc791d7d6902248d851da98616a57.zip
Auto merge of #109599 - notriddle:notriddle/use-redundant-glob, r=petrochenkov
diagnostics: account for glob shadowing when linting redundant imports

Fixes #92904
-rw-r--r--compiler/rustc_resolve/src/ident.rs35
-rw-r--r--tests/ui/lint/use-redundant/issue-92904.rs17
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob-parent.rs16
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr17
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob.rs15
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-glob.stderr16
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs21
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-not-parent.rs19
-rw-r--r--tests/ui/lint/use-redundant/use-redundant.rs (renamed from tests/ui/lint/use-redundant.rs)0
-rw-r--r--tests/ui/lint/use-redundant/use-redundant.stderr (renamed from tests/ui/lint/use-redundant.stderr)0
10 files changed, 142 insertions, 14 deletions
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 06206efb9ab..7ff440e49aa 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -869,17 +869,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let resolution =
             self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
 
-        if let Some(Finalize { path_span, report_private, .. }) = finalize {
-            // If the primary binding is unusable, search further and return the shadowed glob
-            // binding if it exists. What we really want here is having two separate scopes in
-            // a module - one for non-globs and one for globs, but until that's done use this
-            // hack to avoid inconsistent resolution ICEs during import validation.
-            let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map(
-                |binding| match (binding, ignore_binding) {
+        // If the primary binding is unusable, search further and return the shadowed glob
+        // binding if it exists. What we really want here is having two separate scopes in
+        // a module - one for non-globs and one for globs, but until that's done use this
+        // hack to avoid inconsistent resolution ICEs during import validation.
+        let binding =
+            [resolution.binding, resolution.shadowed_glob].into_iter().find_map(|binding| {
+                match (binding, ignore_binding) {
                     (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
                     _ => binding,
-                },
-            );
+                }
+            });
+
+        if let Some(Finalize { path_span, report_private, .. }) = finalize {
             let Some(binding) = binding else {
                 return Err((Determined, Weak::No));
             };
@@ -927,15 +929,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
-            if let Some(ignored) = ignore_binding && ptr::eq(binding, ignored) {
-                return Err((Determined, Weak::No));
-            }
             let usable = this.is_accessible_from(binding.vis, parent_scope.module);
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
         };
 
         // Items and single imports are not shadowable, if we have one, then it's determined.
-        if let Some(binding) = resolution.binding {
+        if let Some(binding) = binding {
             if !binding.is_glob_import() {
                 return check_usable(self, binding);
             }
@@ -952,6 +951,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if !self.is_accessible_from(import_vis, parent_scope.module) {
                 continue;
             }
+            if let Some(ignored) = ignore_binding &&
+                let NameBindingKind::Import { import, .. } = ignored.kind &&
+                ptr::eq(import, &**single_import) {
+                // Ignore not just the binding itself, but if it has a shadowed_glob,
+                // ignore that, too, because this loop is supposed to only process
+                // named imports.
+                continue;
+            }
             let Some(module) = single_import.imported_module.get() else {
                 return Err((Undetermined, Weak::No));
             };
@@ -989,7 +996,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
         // shadowing is enabled, see `macro_expanded_macro_export_errors`).
         let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
-        if let Some(binding) = resolution.binding {
+        if let Some(binding) = binding {
             if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
                 return check_usable(self, binding);
             } else {
diff --git a/tests/ui/lint/use-redundant/issue-92904.rs b/tests/ui/lint/use-redundant/issue-92904.rs
new file mode 100644
index 00000000000..511d9d263cf
--- /dev/null
+++ b/tests/ui/lint/use-redundant/issue-92904.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+pub struct Foo(bar::Bar);
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+pub fn warning() -> Foo {
+    use bar::*;
+    #[deny(unused_imports)]
+    use self::Foo; // no error
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
new file mode 100644
index 00000000000..6b1e018d2dc
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
@@ -0,0 +1,16 @@
+// check-pass
+#![warn(unused_imports)]
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+use bar::*;
+
+pub fn warning() -> Foo {
+    use bar::Foo; //~ WARNING imported redundantly
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr
new file mode 100644
index 00000000000..2c3b3345270
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr
@@ -0,0 +1,17 @@
+warning: the item `Foo` is imported redundantly
+  --> $DIR/use-redundant-glob-parent.rs:12:9
+   |
+LL | use bar::*;
+   |     ------ the item `Foo` is already imported here
+...
+LL |     use bar::Foo;
+   |         ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/use-redundant-glob-parent.rs:2:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.rs b/tests/ui/lint/use-redundant/use-redundant-glob.rs
new file mode 100644
index 00000000000..bd9e51b6f59
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob.rs
@@ -0,0 +1,15 @@
+// check-pass
+#![warn(unused_imports)]
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+pub fn warning() -> bar::Foo {
+    use bar::*;
+    use bar::Foo; //~ WARNING imported redundantly
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.stderr b/tests/ui/lint/use-redundant/use-redundant-glob.stderr
new file mode 100644
index 00000000000..d3b406d82b6
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob.stderr
@@ -0,0 +1,16 @@
+warning: the item `Foo` is imported redundantly
+  --> $DIR/use-redundant-glob.rs:11:9
+   |
+LL |     use bar::*;
+   |         ------ the item `Foo` is already imported here
+LL |     use bar::Foo;
+   |         ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/use-redundant-glob.rs:2:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs b/tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs
new file mode 100644
index 00000000000..0fb60840f8a
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs
@@ -0,0 +1,21 @@
+// check-pass
+#![allow(nonstandard_style)]
+
+pub mod bar {
+    pub struct Foo { pub bar: Bar }
+    pub struct Bar(pub char);
+}
+
+pub mod x {
+    use crate::bar;
+    pub const Foo: bar::Bar = bar::Bar('a');
+}
+
+pub fn warning() -> bar::Foo {
+    #![deny(unused_imports)] // no error
+    use bar::*;
+    use x::Foo;
+    Foo { bar: Foo }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-not-parent.rs b/tests/ui/lint/use-redundant/use-redundant-not-parent.rs
new file mode 100644
index 00000000000..c97a3d34163
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-not-parent.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+pub mod x {
+    pub struct Foo(pub crate::bar::Bar);
+}
+
+pub fn warning() -> x::Foo {
+    use bar::*;
+    #[deny(unused_imports)]
+    use x::Foo; // no error
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant.rs b/tests/ui/lint/use-redundant/use-redundant.rs
index 53315dcf638..53315dcf638 100644
--- a/tests/ui/lint/use-redundant.rs
+++ b/tests/ui/lint/use-redundant/use-redundant.rs
diff --git a/tests/ui/lint/use-redundant.stderr b/tests/ui/lint/use-redundant/use-redundant.stderr
index c861a1956e1..c861a1956e1 100644
--- a/tests/ui/lint/use-redundant.stderr
+++ b/tests/ui/lint/use-redundant/use-redundant.stderr