about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-14 05:37:08 +0000
committerbors <bors@rust-lang.org>2023-06-14 05:37:08 +0000
commit57c215b08e18054c64428e00a291b45dc690d9de (patch)
tree285c685ef97e21d679275b84280d862fe27fc364
parentfa8762b7b6c2b75d6c83fb011ee8fa4874168829 (diff)
parent623b1d4b62be3d3f106f5c273443d71326356585 (diff)
downloadrust-57c215b08e18054c64428e00a291b45dc690d9de.tar.gz
rust-57c215b08e18054c64428e00a291b45dc690d9de.zip
Auto merge of #112609 - matthiaskrgr:rollup-er6weld, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #112197 (Erase regions even if normalization fails in writeback (in new solver))
 - #112495 (fix(resolve): update shadowed_glob more precision)
 - #112520 (Fix the overflow issue for transmute_generic_consts)
 - #112571 (rustdoc-search: search never type with `!`)
 - #112581 ([rustdoc] Fix URL encoding of % sign)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs11
-rw-r--r--compiler/rustc_resolve/src/imports.rs16
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/static/js/search.js48
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/rustdoc-js-std/never.js20
-rw-r--r--tests/rustdoc-js-std/parser-errors.js9
-rw-r--r--tests/rustdoc-js-std/parser-ident.js80
-rw-r--r--tests/rustdoc-js-std/parser-returned.js8
-rw-r--r--tests/rustdoc-js/never-search.js46
-rw-r--r--tests/rustdoc-js/never-search.rs13
-rw-r--r--tests/ui/const-generics/issue-112505-overflow.rs7
-rw-r--r--tests/ui/const-generics/issue-112505-overflow.stderr12
-rw-r--r--tests/ui/for/issue-20605.current.stderr (renamed from tests/ui/issues/issue-20605.stderr)2
-rw-r--r--tests/ui/for/issue-20605.next.stderr25
-rw-r--r--tests/ui/for/issue-20605.rs11
-rw-r--r--tests/ui/issues/issue-20605.rs6
-rw-r--r--tests/ui/resolve/issue-105069.stderr4
-rw-r--r--tests/ui/resolve/issue-109153.rs14
-rw-r--r--tests/ui/resolve/issue-109153.stderr23
21 files changed, 331 insertions, 39 deletions
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 3c5eafd9484..362c07431e0 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -82,8 +82,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Try to display a sensible error with as much information as possible.
         let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
-            Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
             Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+            Ok(SizeSkeleton::Known(size)) => {
+                if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
+                    format!("{} bits", v)
+                } else {
+                    // `u128` should definitely be able to hold the size of different architectures
+                    // larger sizes should be reported as error `are too big for the current architecture`
+                    // otherwise we have a bug somewhere
+                    bug!("{:?} overflow for u128", size)
+                }
+            }
             Ok(SizeSkeleton::Generic(size)) => {
                 if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) {
                     format!("{size} bytes")
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index a395858262f..29abe921bbd 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -136,7 +136,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
     fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
         debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
-        assert!(!ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions());
+        assert!(
+            !ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions(),
+            "{ty} can't be put into typeck results"
+        );
         self.typeck_results.node_types_mut().insert(hir_id, ty);
     }
 
@@ -803,7 +806,11 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
                 // We must normalize erasing regions here, since later lints
                 // expect that types that show up in the typeck are fully
                 // normalized.
-                self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t).unwrap_or(t)
+                if let Ok(t) = self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t) {
+                    t
+                } else {
+                    EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t)
+                }
             }
             Ok(t) => {
                 // Do not anonymize late-bound regions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 7f944fb5745..47d8e5993fd 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -338,7 +338,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         } else {
                             resolution.binding = Some(nonglob_binding);
                         }
-                        resolution.shadowed_glob = Some(glob_binding);
+
+                        if let Some(old_binding) = resolution.shadowed_glob {
+                            assert!(old_binding.is_glob_import());
+                            if glob_binding.res() != old_binding.res() {
+                                resolution.shadowed_glob = Some(this.ambiguity(
+                                    AmbiguityKind::GlobVsGlob,
+                                    old_binding,
+                                    glob_binding,
+                                ));
+                            } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
+                                resolution.shadowed_glob = Some(glob_binding);
+                            }
+                        } else {
+                            resolution.shadowed_glob = Some(glob_binding);
+                        }
                     }
                     (false, false) => {
                         return Err(old_binding);
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f205ff15ec3..5bd9389a400 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1940,8 +1940,6 @@ pub(crate) fn small_url_encode(s: String) -> String {
             // While the same is not true for hashes, rustdoc only needs to be
             // consistent with itself when encoding them.
             st += "+";
-        } else if b == b'%' {
-            st += "%%";
         } else {
             write!(st, "%{:02X}", b).unwrap();
         }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 984358396ab..1ccfca8d0d5 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -386,6 +386,35 @@ function initSearch(rawSearchIndex) {
         if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
             throw ["You cannot have more than one element if you use quotes"];
         }
+        const typeFilter = parserState.typeFilter;
+        parserState.typeFilter = null;
+        if (name === "!") {
+            if (typeFilter !== null && typeFilter !== "primitive") {
+                throw [
+                    "Invalid search type: primitive never type ",
+                    "!",
+                    " and ",
+                    typeFilter,
+                    " both specified",
+                ];
+            }
+            if (generics.length !== 0) {
+                throw [
+                    "Never type ",
+                    "!",
+                    " does not accept generic parameters",
+                ];
+            }
+            return {
+                name: "never",
+                id: -1,
+                fullPath: ["never"],
+                pathWithoutLast: [],
+                pathLast: "never",
+                generics: [],
+                typeFilter: "primitive",
+            };
+        }
         const pathSegments = name.split("::");
         if (pathSegments.length > 1) {
             for (let i = 0, len = pathSegments.length; i < len; ++i) {
@@ -399,6 +428,13 @@ function initSearch(rawSearchIndex) {
                     }
                     throw ["Unexpected ", "::::"];
                 }
+
+                if (pathSegment === "!") {
+                    pathSegments[i] = "never";
+                    if (i !== 0) {
+                        throw ["Never type ", "!", " is not associated item"];
+                    }
+                }
             }
         }
         // In case we only have something like `<p>`, there is no name.
@@ -409,8 +445,6 @@ function initSearch(rawSearchIndex) {
         if (isInGenerics) {
             parserState.genericsElems += 1;
         }
-        const typeFilter = parserState.typeFilter;
-        parserState.typeFilter = null;
         return {
             name: name,
             id: -1,
@@ -459,10 +493,11 @@ function initSearch(rawSearchIndex) {
                         break;
                     }
                     if (foundExclamation !== -1) {
-                        if (start <= (end - 2)) {
+                        if (foundExclamation !== start &&
+                            isIdentCharacter(parserState.userQuery[foundExclamation - 1])
+                        ) {
                             throw ["Cannot have associated items in macros"];
                         } else {
-                            // if start == end - 1, we got the never type
                             // while the never type has no associated macros, we still
                             // can parse a path like that
                             foundExclamation = -1;
@@ -478,7 +513,10 @@ function initSearch(rawSearchIndex) {
             end = parserState.pos;
         }
         // if start == end - 1, we got the never type
-        if (foundExclamation !== -1 && start <= (end - 2)) {
+        if (foundExclamation !== -1 &&
+            foundExclamation !== start &&
+            isIdentCharacter(parserState.userQuery[foundExclamation - 1])
+        ) {
             if (parserState.typeFilter === null) {
                 parserState.typeFilter = "macro";
             } else if (parserState.typeFilter !== "macro") {
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 5c6a9487788..55bf38110a6 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
 
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
-const ISSUES_ENTRY_LIMIT: usize = 1898;
+const ISSUES_ENTRY_LIMIT: usize = 1896;
 const ROOT_ENTRY_LIMIT: usize = 870;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/rustdoc-js-std/never.js b/tests/rustdoc-js-std/never.js
index ed3776b3c2a..27d415b5e48 100644
--- a/tests/rustdoc-js-std/never.js
+++ b/tests/rustdoc-js-std/never.js
@@ -1,6 +1,14 @@
-const EXPECTED = {
-    'query': '!',
-    'others': [
-        { 'path': 'std', 'name': 'never' },
-    ],
-};
+const EXPECTED = [
+    {
+        'query': '!',
+        'others': [
+            { 'path': 'std', 'name': 'never' },
+        ],
+    },
+    {
+        'query': '!::clone',
+        'others': [
+            { 'path': 'std::never', 'name': 'clone' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js
index aa8ee86d672..af7f63f99cb 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -360,6 +360,15 @@ const PARSED = [
         error: 'Invalid search type: macro `!` and `mod` both specified',
     },
     {
+        query: "mod:!",
+        elems: [],
+        foundElems: 0,
+        original: "mod:!",
+        returned: [],
+        userQuery: "mod:!",
+        error: 'Invalid search type: primitive never type `!` and `mod` both specified',
+    },
+    {
         query: "a!::a",
         elems: [],
         foundElems: 0,
diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js
index d9ee5fb564b..f65a7ce6692 100644
--- a/tests/rustdoc-js-std/parser-ident.js
+++ b/tests/rustdoc-js-std/parser-ident.js
@@ -8,11 +8,12 @@ const PARSED = [
             pathLast: "r",
             generics: [
                 {
-                    name: "!",
-                    fullPath: ["!"],
+                    name: "never",
+                    fullPath: ["never"],
                     pathWithoutLast: [],
-                    pathLast: "!",
+                    pathLast: "never",
                     generics: [],
+                    typeFilter: 15,
                 },
             ],
             typeFilter: -1,
@@ -26,12 +27,12 @@ const PARSED = [
     {
         query: "!",
         elems: [{
-            name: "!",
-            fullPath: ["!"],
+            name: "never",
+            fullPath: ["never"],
             pathWithoutLast: [],
-            pathLast: "!",
+            pathLast: "never",
             generics: [],
-            typeFilter: -1,
+            typeFilter: 15,
         }],
         foundElems: 1,
         original: "!",
@@ -65,11 +66,20 @@ const PARSED = [
         error: "Cannot have associated items in macros",
     },
     {
+        query: "!<T>",
+        elems: [],
+        foundElems: 0,
+        original: "!<T>",
+        returned: [],
+        userQuery: "!<t>",
+        error: "Never type `!` does not accept generic parameters",
+    },
+    {
         query: "!::b",
         elems: [{
             name: "!::b",
-            fullPath: ["!", "b"],
-            pathWithoutLast: ["!"],
+            fullPath: ["never", "b"],
+            pathWithoutLast: ["never"],
             pathLast: "b",
             generics: [],
             typeFilter: -1,
@@ -81,6 +91,58 @@ const PARSED = [
         error: null,
     },
     {
+        query: "b::!",
+        elems: [],
+        foundElems: 0,
+        original: "b::!",
+        returned: [],
+        userQuery: "b::!",
+        error: "Never type `!` is not associated item",
+    },
+    {
+        query: "!::!",
+        elems: [],
+        foundElems: 0,
+        original: "!::!",
+        returned: [],
+        userQuery: "!::!",
+        error: "Never type `!` is not associated item",
+    },
+    {
+        query: "b::!::c",
+        elems: [],
+        foundElems: 0,
+        original: "b::!::c",
+        returned: [],
+        userQuery: "b::!::c",
+        error: "Never type `!` is not associated item",
+    },
+    {
+        query: "!::b<T>",
+        elems: [{
+            name: "!::b",
+            fullPath: ["never", "b"],
+            pathWithoutLast: ["never"],
+            pathLast: "b",
+            generics: [
+                {
+                    name: "t",
+                    fullPath: ["t"],
+                    pathWithoutLast: [],
+                    pathLast: "t",
+                    generics: [],
+                    typeFilter: -1,
+                }
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "!::b<T>",
+        returned: [],
+        userQuery: "!::b<t>",
+        error: null,
+    },
+    {
         query: "a!::b!",
         elems: [],
         foundElems: 0,
diff --git a/tests/rustdoc-js-std/parser-returned.js b/tests/rustdoc-js-std/parser-returned.js
index 665e2a9b2e3..6ea86609115 100644
--- a/tests/rustdoc-js-std/parser-returned.js
+++ b/tests/rustdoc-js-std/parser-returned.js
@@ -84,12 +84,12 @@ const PARSED = [
         foundElems: 1,
         original: "-> !",
         returned: [{
-            name: "!",
-            fullPath: ["!"],
+            name: "never",
+            fullPath: ["never"],
             pathWithoutLast: [],
-            pathLast: "!",
+            pathLast: "never",
             generics: [],
-            typeFilter: -1,
+            typeFilter: 15,
         }],
         userQuery: "-> !",
         error: null,
diff --git a/tests/rustdoc-js/never-search.js b/tests/rustdoc-js/never-search.js
new file mode 100644
index 00000000000..ed24d693133
--- /dev/null
+++ b/tests/rustdoc-js/never-search.js
@@ -0,0 +1,46 @@
+// exact-check
+
+const EXPECTED = [
+    {
+        'query': '-> !',
+        'others': [
+            { 'path': 'never_search', 'name': 'loops' },
+        ],
+    },
+    {
+        'query': '-> never',
+        'others': [
+            { 'path': 'never_search', 'name': 'loops' },
+            { 'path': 'never_search', 'name': 'returns' },
+        ],
+    },
+    {
+        'query': '!',
+        'in_args': [
+            { 'path': 'never_search', 'name': 'impossible' },
+            { 'path': 'never_search', 'name': 'box_impossible' },
+        ],
+    },
+    {
+        'query': 'never',
+        'in_args': [
+            { 'path': 'never_search', 'name': 'impossible' },
+            { 'path': 'never_search', 'name': 'uninteresting' },
+            { 'path': 'never_search', 'name': 'box_impossible' },
+            { 'path': 'never_search', 'name': 'box_uninteresting' },
+        ],
+    },
+    {
+        'query': 'box<!>',
+        'in_args': [
+            { 'path': 'never_search', 'name': 'box_impossible' },
+        ],
+    },
+    {
+        'query': 'box<never>',
+        'in_args': [
+            { 'path': 'never_search', 'name': 'box_impossible' },
+            { 'path': 'never_search', 'name': 'box_uninteresting' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/never-search.rs b/tests/rustdoc-js/never-search.rs
new file mode 100644
index 00000000000..299b4660dae
--- /dev/null
+++ b/tests/rustdoc-js/never-search.rs
@@ -0,0 +1,13 @@
+#![feature(never_type)]
+
+#[allow(nonstandard_style)]
+pub struct never;
+
+pub fn loops() -> ! { loop {} }
+pub fn returns() -> never { never }
+
+pub fn impossible(x: !) { match x {} }
+pub fn uninteresting(x: never) { match x { never => {} } }
+
+pub fn box_impossible(x: Box<!>) { match *x {} }
+pub fn box_uninteresting(x: Box<never>) { match *x { never => {} } }
diff --git a/tests/ui/const-generics/issue-112505-overflow.rs b/tests/ui/const-generics/issue-112505-overflow.rs
new file mode 100644
index 00000000000..0dd7776d595
--- /dev/null
+++ b/tests/ui/const-generics/issue-112505-overflow.rs
@@ -0,0 +1,7 @@
+#![feature(transmute_generic_consts)]
+
+fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 777777777]; 239] {
+    unsafe { std::mem::transmute(v) } //~ ERROR cannot transmute between types of different sizes
+}
+
+fn main() { }
diff --git a/tests/ui/const-generics/issue-112505-overflow.stderr b/tests/ui/const-generics/issue-112505-overflow.stderr
new file mode 100644
index 00000000000..0432f2fa8be
--- /dev/null
+++ b/tests/ui/const-generics/issue-112505-overflow.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/issue-112505-overflow.rs:4:14
+   |
+LL |     unsafe { std::mem::transmute(v) }
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture)
+   = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (59484438436515561504 bits)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/issues/issue-20605.stderr b/tests/ui/for/issue-20605.current.stderr
index e1858b63989..b9a53cbd4fc 100644
--- a/tests/ui/issues/issue-20605.stderr
+++ b/tests/ui/for/issue-20605.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `dyn Iterator<Item = &'a mut u8>` cannot be known at compilation time
-  --> $DIR/issue-20605.rs:2:17
+  --> $DIR/issue-20605.rs:5:17
    |
 LL |     for item in *things { *item = 0 }
    |                 ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr
new file mode 100644
index 00000000000..5362a68c834
--- /dev/null
+++ b/tests/ui/for/issue-20605.next.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
+  --> $DIR/issue-20605.rs:5:17
+   |
+LL |     for item in *things { *item = 0 }
+   |                 ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
+
+error[E0277]: the size for values of type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` cannot be known at compilation time
+  --> $DIR/issue-20605.rs:5:17
+   |
+LL |     for item in *things { *item = 0 }
+   |                 ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+
+error: the type `<_ as IntoIterator>::IntoIter` is not well-formed
+  --> $DIR/issue-20605.rs:5:17
+   |
+LL |     for item in *things { *item = 0 }
+   |                 ^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs
new file mode 100644
index 00000000000..499271fa92f
--- /dev/null
+++ b/tests/ui/for/issue-20605.rs
@@ -0,0 +1,11 @@
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
+    for item in *things { *item = 0 }
+    //~^ ERROR the size for values of type
+    //[next]~^^ ERROR the type `<_ as IntoIterator>::IntoIter` is not well-formed
+    //[next]~| ERROR the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-20605.rs b/tests/ui/issues/issue-20605.rs
deleted file mode 100644
index 17b7d32ebf5..00000000000
--- a/tests/ui/issues/issue-20605.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
-    for item in *things { *item = 0 }
-//~^ ERROR the size for values of type
-}
-
-fn main() {}
diff --git a/tests/ui/resolve/issue-105069.stderr b/tests/ui/resolve/issue-105069.stderr
index 1e6c9c6e2dc..a049cac830a 100644
--- a/tests/ui/resolve/issue-105069.stderr
+++ b/tests/ui/resolve/issue-105069.stderr
@@ -4,17 +4,19 @@ error[E0659]: `V` is ambiguous
 LL | use V;
    |     ^ ambiguous name
    |
-   = note: ambiguous because of multiple potential import sources
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `V` could refer to the variant imported here
   --> $DIR/issue-105069.rs:1:5
    |
 LL | use self::A::*;
    |     ^^^^^^^^^^
+   = help: consider adding an explicit import of `V` to disambiguate
 note: `V` could also refer to the variant imported here
   --> $DIR/issue-105069.rs:3:5
    |
 LL | use self::B::*;
    |     ^^^^^^^^^^
+   = help: consider adding an explicit import of `V` to disambiguate
 
 error: aborting due to previous error
 
diff --git a/tests/ui/resolve/issue-109153.rs b/tests/ui/resolve/issue-109153.rs
new file mode 100644
index 00000000000..bff6c911236
--- /dev/null
+++ b/tests/ui/resolve/issue-109153.rs
@@ -0,0 +1,14 @@
+use foo::*;
+
+mod foo {
+    pub mod bar {
+        pub mod bar {
+            pub mod bar {}
+        }
+    }
+}
+
+use bar::bar; //~ ERROR `bar` is ambiguous
+use bar::*;
+
+fn main() { }
diff --git a/tests/ui/resolve/issue-109153.stderr b/tests/ui/resolve/issue-109153.stderr
new file mode 100644
index 00000000000..1a345d2a3e3
--- /dev/null
+++ b/tests/ui/resolve/issue-109153.stderr
@@ -0,0 +1,23 @@
+error[E0659]: `bar` is ambiguous
+  --> $DIR/issue-109153.rs:11:5
+   |
+LL | use bar::bar;
+   |     ^^^ ambiguous name
+   |
+   = note: ambiguous because of multiple glob imports of a name in the same module
+note: `bar` could refer to the module imported here
+  --> $DIR/issue-109153.rs:1:5
+   |
+LL | use foo::*;
+   |     ^^^^^^
+   = help: consider adding an explicit import of `bar` to disambiguate
+note: `bar` could also refer to the module imported here
+  --> $DIR/issue-109153.rs:12:5
+   |
+LL | use bar::*;
+   |     ^^^^^^
+   = help: consider adding an explicit import of `bar` to disambiguate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.