about summary refs log tree commit diff
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs6
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs137
-rw-r--r--compiler/rustc_resolve/src/ident.rs8
-rw-r--r--compiler/rustc_resolve/src/imports.rs140
-rw-r--r--compiler/rustc_resolve/src/late.rs193
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs70
-rw-r--r--compiler/rustc_resolve/src/lib.rs30
-rw-r--r--compiler/rustc_resolve/src/macros.rs31
9 files changed, 397 insertions, 220 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index ff63e4e33cb..2f432799022 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -41,6 +41,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a>
         arenas.alloc_name_binding(NameBindingData {
             kind: NameBindingKind::Module(self.0),
             ambiguity: None,
+            warn_ambiguity: false,
             vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
@@ -53,6 +54,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span,
         arenas.alloc_name_binding(NameBindingData {
             kind: NameBindingKind::Res(self.0),
             ambiguity: None,
+            warn_ambiguity: false,
             vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
@@ -69,7 +71,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     {
         let binding = def.to_name_binding(self.arenas);
         let key = self.new_disambiguated_key(ident, ns);
-        if let Err(old_binding) = self.try_define(parent, key, binding) {
+        if let Err(old_binding) = self.try_define(parent, key, binding, false) {
             self.report_conflict(parent, ident, ns, old_binding, binding);
         }
     }
@@ -999,7 +1001,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         allow_shadowing: bool,
     ) {
         if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
-            let msg = format!("`{}` is already in scope", name);
+            let msg = format!("`{name}` is already in scope");
             let note =
                 "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
             self.r.tcx.sess.struct_span_err(span, msg).note(note).emit();
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 3228e8d52f0..7dbbd4c34ea 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -362,7 +362,7 @@ impl Resolver<'_, '_> {
             let mut span_snippets = spans
                 .iter()
                 .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
-                    Ok(s) => Some(format!("`{}`", s)),
+                    Ok(s) => Some(format!("`{s}`")),
                     _ => None,
                 })
                 .collect::<Vec<String>>();
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 2cfde2f62d8..cd1a9b934cf 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -5,10 +5,8 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{
-    pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
-};
-use rustc_errors::{struct_span_err, SuggestionStyle};
+use rustc_errors::{pluralize, report_ambiguity_error, struct_span_err, SuggestionStyle};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
@@ -17,8 +15,9 @@ use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
+use rustc_session::lint::builtin::AMBIGUOUS_GLOB_IMPORTS;
 use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
-use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiagnostics};
 use rustc_session::Session;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
@@ -135,7 +134,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         for ambiguity_error in &self.ambiguity_errors {
-            self.report_ambiguity_error(ambiguity_error);
+            let diag = self.ambiguity_diagnostics(ambiguity_error);
+            if ambiguity_error.warning {
+                let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
+                    unreachable!()
+                };
+                self.lint_buffer.buffer_lint_with_diagnostic(
+                    AMBIGUOUS_GLOB_IMPORTS,
+                    import.root_id,
+                    ambiguity_error.ident.span,
+                    diag.msg.to_string(),
+                    BuiltinLintDiagnostics::AmbiguousGlobImports { diag },
+                );
+            } else {
+                let mut err = struct_span_err!(self.tcx.sess, diag.span, E0659, "{}", &diag.msg);
+                report_ambiguity_error(&mut err, diag);
+                err.emit();
+            }
         }
 
         let mut reported_spans = FxHashSet::default();
@@ -228,7 +243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             (TypeNS, _) => "type",
         };
 
-        let msg = format!("the name `{}` is defined multiple times", name);
+        let msg = format!("the name `{name}` is defined multiple times");
 
         let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
             (true, true) => struct_span_err!(self.tcx.sess, span, E0259, "{}", msg),
@@ -250,11 +265,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             container
         ));
 
-        err.span_label(span, format!("`{}` re{} here", name, new_participle));
+        err.span_label(span, format!("`{name}` re{new_participle} here"));
         if !old_binding.span.is_dummy() && old_binding.span != span {
             err.span_label(
                 self.tcx.sess.source_map().guess_head_span(old_binding.span),
-                format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
+                format!("previous {old_noun} of the {old_kind} `{name}` here"),
             );
         }
 
@@ -343,15 +358,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         binding_span: Span,
     ) {
         let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
-            format!("Other{}", name)
+            format!("Other{name}")
         } else {
-            format!("other_{}", name)
+            format!("other_{name}")
         };
 
         let mut suggestion = None;
         match import.kind {
             ImportKind::Single { type_ns_only: true, .. } => {
-                suggestion = Some(format!("self as {}", suggested_name))
+                suggestion = Some(format!("self as {suggested_name}"))
             }
             ImportKind::Single { source, .. } => {
                 if let Some(pos) =
@@ -587,11 +602,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     let sugg_msg = "try using a local generic parameter instead";
                     let name = self.tcx.item_name(def_id);
                     let (span, snippet) = if span.is_empty() {
-                        let snippet = format!("<{}>", name);
+                        let snippet = format!("<{name}>");
                         (span, snippet)
                     } else {
                         let span = sm.span_through_char(span, '<').shrink_to_hi();
-                        let snippet = format!("{}, ", name);
+                        let snippet = format!("{name}, ");
                         (span, snippet)
                     };
                     // Suggest the modification to the user
@@ -652,7 +667,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     name,
                 );
                 for sp in target_sp {
-                    err.span_label(sp, format!("pattern doesn't bind `{}`", name));
+                    err.span_label(sp, format!("pattern doesn't bind `{name}`"));
                 }
                 for sp in origin_sp {
                     err.span_label(sp, "variable not in all patterns");
@@ -679,8 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if import_suggestions.is_empty() {
                         let help_msg = format!(
                             "if you meant to match on a variant or a `const` item, consider \
-                             making the path in the pattern qualified: `path::to::ModOrType::{}`",
-                            name,
+                             making the path in the pattern qualified: `path::to::ModOrType::{name}`",
                         );
                         err.span_help(span, help_msg);
                     }
@@ -938,8 +952,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let mut err = self.tcx.sess.struct_span_err_with_code(
                     span,
                     format!(
-                        "item `{}` is an associated {}, which doesn't match its trait `{}`",
-                        name, kind, trait_path,
+                        "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`",
                     ),
                     code,
                 );
@@ -1395,7 +1408,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let head_span = source_map.guess_head_span(span);
             err.subdiagnostic(ConsiderAddingADerive {
                 span: head_span.shrink_to_lo(),
-                suggestion: format!("#[derive(Default)]\n")
+                suggestion: "#[derive(Default)]\n".to_string(),
             });
         }
         for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
@@ -1412,10 +1425,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         "a function-like macro".to_string()
                     }
                     Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
-                        format!("an attribute: `#[{}]`", ident)
+                        format!("an attribute: `#[{ident}]`")
                     }
                     Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
-                        format!("a derive macro: `#[derive({})]`", ident)
+                        format!("a derive macro: `#[derive({ident})]`")
                     }
                     Res::ToolMod => {
                         // Don't confuse the user with tool modules.
@@ -1436,7 +1449,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if !import.span.is_dummy() {
                         err.span_note(
                             import.span,
-                            format!("`{}` is imported here, but it is {}", ident, desc),
+                            format!("`{ident}` is imported here, but it is {desc}"),
                         );
                         // Silence the 'unused import' warning we might get,
                         // since this diagnostic already covers that import.
@@ -1444,7 +1457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         return;
                     }
                 }
-                err.note(format!("`{}` is in scope, but it is {}", ident, desc));
+                err.note(format!("`{ident}` is in scope, but it is {desc}"));
                 return;
             }
         }
@@ -1540,20 +1553,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
-    fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
-        let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
+    fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
+        let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
         let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
             // We have to print the span-less alternative first, otherwise formatting looks bad.
             (b2, b1, misc2, misc1, true)
         } else {
             (b1, b2, misc1, misc2, false)
         };
-
-        let mut err = struct_span_err!(self.tcx.sess, ident.span, E0659, "`{ident}` is ambiguous");
-        err.span_label(ident.span, "ambiguous name");
-        err.note(format!("ambiguous because of {}", kind.descr()));
-
-        let mut could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
+        let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
             let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
             let note_msg = format!("`{ident}` could{also} refer to {what}");
 
@@ -1579,16 +1587,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
             }
 
-            err.span_note(b.span, note_msg);
-            for (i, help_msg) in help_msgs.iter().enumerate() {
-                let or = if i == 0 { "" } else { "or " };
-                err.help(format!("{}{}", or, help_msg));
-            }
+            (
+                b.span,
+                note_msg,
+                help_msgs
+                    .iter()
+                    .enumerate()
+                    .map(|(i, help_msg)| {
+                        let or = if i == 0 { "" } else { "or " };
+                        format!("{or}{help_msg}")
+                    })
+                    .collect::<Vec<_>>(),
+            )
         };
-
-        could_refer_to(b1, misc1, "");
-        could_refer_to(b2, misc2, " also");
-        err.emit();
+        let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, "");
+        let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also");
+
+        AmbiguityErrorDiag {
+            msg: format!("`{ident}` is ambiguous"),
+            span: ident.span,
+            label_span: ident.span,
+            label_msg: "ambiguous name".to_string(),
+            note_msg: format!("ambiguous because of {}", kind.descr()),
+            b1_span,
+            b1_note_msg,
+            b1_help_msgs,
+            b2_span,
+            b2_note_msg,
+            b2_help_msgs,
+        }
     }
 
     /// If the binding refers to a tuple struct constructor with fields,
@@ -1626,7 +1653,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let descr = get_descr(binding);
         let mut err =
             struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
-        err.span_label(ident.span, format!("private {}", descr));
+        err.span_label(ident.span, format!("private {descr}"));
 
         if let Some((this_res, outer_ident)) = outermost_res {
             let import_suggestions = self.lookup_import_candidates(
@@ -1718,7 +1745,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if next_binding.is_none() && let Some(span) = non_exhaustive {
                 note_span.push_span_label(
                     span,
-                    format!("cannot be constructed because it is `#[non_exhaustive]`"),
+                    "cannot be constructed because it is `#[non_exhaustive]`",
                 );
             }
             err.span_note(note_span, msg);
@@ -1811,7 +1838,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 _ => format!("`{parent}`"),
             };
 
-            let mut msg = format!("could not find `{}` in {}", ident, parent);
+            let mut msg = format!("could not find `{ident}` in {parent}");
             if ns == TypeNS || ns == ValueNS {
                 let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
                 let binding = if let Some(module) = module {
@@ -1926,12 +1953,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let suggestion = match_span.map(|span| {
                 (
                     vec![(span, String::from(""))],
-                    format!("`{}` is defined here, but is not a type", ident),
+                    format!("`{ident}` is defined here, but is not a type"),
                     Applicability::MaybeIncorrect,
                 )
             });
 
-            (format!("use of undeclared type `{}`", ident), suggestion)
+            (format!("use of undeclared type `{ident}`"), suggestion)
         } else {
             let mut suggestion = None;
             if ident.name == sym::alloc {
@@ -1953,7 +1980,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     },
                 )
             });
-            (format!("use of undeclared crate or module `{}`", ident), suggestion)
+            (format!("use of undeclared crate or module `{ident}`"), suggestion)
         }
     }
 
@@ -2137,16 +2164,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let module_name = crate_module.kind.name().unwrap();
             let import_snippet = match import.kind {
                 ImportKind::Single { source, target, .. } if source != target => {
-                    format!("{} as {}", source, target)
+                    format!("{source} as {target}")
                 }
-                _ => format!("{}", ident),
+                _ => format!("{ident}"),
             };
 
             let mut corrections: Vec<(Span, String)> = Vec::new();
             if !import.is_nested() {
                 // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
                 // intermediate segments.
-                corrections.push((import.span, format!("{}::{}", module_name, import_snippet)));
+                corrections.push((import.span, format!("{module_name}::{import_snippet}")));
             } else {
                 // Find the binding span (and any trailing commas and spaces).
                 //   ie. `use a::b::{c, d, e};`
@@ -2213,11 +2240,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         start_point,
                         if has_nested {
                             // In this case, `start_snippet` must equal '{'.
-                            format!("{}{}, ", start_snippet, import_snippet)
+                            format!("{start_snippet}{import_snippet}, ")
                         } else {
                             // In this case, add a `{`, then the moved import, then whatever
                             // was there before.
-                            format!("{{{}, {}", import_snippet, start_snippet)
+                            format!("{{{import_snippet}, {start_snippet}")
                         },
                     ));
 
@@ -2634,9 +2661,9 @@ fn show_candidates(
                 "item"
             };
             let plural_descr =
-                if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) };
+                if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
 
-            let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
+            let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
             let mut has_colon = false;
 
             let mut spans = Vec::new();
@@ -2657,7 +2684,7 @@ fn show_candidates(
 
             let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
             for (name, span) in spans {
-                multi_span.push_span_label(span, format!("`{}`: not accessible", name));
+                multi_span.push_span_label(span, format!("`{name}`: not accessible"));
             }
 
             for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index de431444769..3bd9cea27ce 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -677,6 +677,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                         ident: orig_ident,
                                         b1: innermost_binding,
                                         b2: binding,
+                                        warning: false,
                                         misc1: misc(innermost_flags),
                                         misc2: misc(flags),
                                     });
@@ -905,6 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     ident,
                     b1: binding,
                     b2: shadowed_glob,
+                    warning: false,
                     misc1: AmbiguityErrorMisc::None,
                     misc2: AmbiguityErrorMisc::None,
                 });
@@ -1443,12 +1445,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     let name_str = if name == kw::PathRoot {
                         "crate root".to_string()
                     } else {
-                        format!("`{}`", name)
+                        format!("`{name}`")
                     };
                     let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
-                        format!("global paths cannot start with {}", name_str)
+                        format!("global paths cannot start with {name_str}")
                     } else {
-                        format!("{} in paths can only be used in start position", name_str)
+                        format!("{name_str} in paths can only be used in start position")
                     };
                     (label, None)
                 });
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 526fc9c3aa5..7f436438e8a 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -284,6 +284,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         self.arenas.alloc_name_binding(NameBindingData {
             kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
             ambiguity: None,
+            warn_ambiguity: false,
             span: import.span,
             vis,
             expansion: import.parent_scope.expansion,
@@ -291,16 +292,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     /// Define the name or return the existing binding if there is a collision.
+    /// `update` indicates if the definition is a redefinition of an existing binding.
     pub(crate) fn try_define(
         &mut self,
         module: Module<'a>,
         key: BindingKey,
         binding: NameBinding<'a>,
+        warn_ambiguity: bool,
     ) -> Result<(), NameBinding<'a>> {
         let res = binding.res();
         self.check_reserved_macro_name(key.ident, res);
         self.set_binding_parent_module(binding, module);
-        self.update_resolution(module, key, |this, resolution| {
+        self.update_resolution(module, key, warn_ambiguity, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
                 if res == Res::Err && old_binding.res() != Res::Err {
                     // Do not override real bindings with `Res::Err`s from error recovery.
@@ -308,15 +311,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
                 match (old_binding.is_glob_import(), binding.is_glob_import()) {
                     (true, true) => {
-                        if res != old_binding.res() {
-                            resolution.binding = Some(this.ambiguity(
-                                AmbiguityKind::GlobVsGlob,
-                                old_binding,
-                                binding,
-                            ));
+                        // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity.
+                        if !binding.is_ambiguity()
+                            && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind
+                            && let NameBindingKind::Import { import, .. } = binding.kind
+                            && old_import == import {
+                            // We should replace the `old_binding` with `binding` regardless
+                            // of whether they has same resolution or not when they are
+                            // imported from the same glob-import statement.
+                            // However we currently using `Some(old_binding)` for back compact
+                            // purposes.
+                            // This case can be removed after once `Undetermined` is prepared
+                            // for glob-imports.
+                        } else if res != old_binding.res() {
+                            let binding = if warn_ambiguity {
+                                this.warn_ambiguity(
+                                    AmbiguityKind::GlobVsGlob,
+                                    old_binding,
+                                    binding,
+                                )
+                            } else {
+                                this.ambiguity(
+                                    AmbiguityKind::GlobVsGlob,
+                                    old_binding,
+                                    binding,
+                                )
+                            };
+                            resolution.binding = Some(binding);
                         } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
                             // We are glob-importing the same item but with greater visibility.
                             resolution.binding = Some(binding);
+                        } else if binding.is_ambiguity() {
+                            resolution.binding =
+                                Some(self.arenas.alloc_name_binding(NameBindingData {
+                                    warn_ambiguity: true,
+                                    ..(*binding).clone()
+                                }));
                         }
                     }
                     (old_glob @ true, false) | (old_glob @ false, true) => {
@@ -374,29 +404,52 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         })
     }
 
+    fn warn_ambiguity(
+        &self,
+        kind: AmbiguityKind,
+        primary_binding: NameBinding<'a>,
+        secondary_binding: NameBinding<'a>,
+    ) -> NameBinding<'a> {
+        self.arenas.alloc_name_binding(NameBindingData {
+            ambiguity: Some((secondary_binding, kind)),
+            warn_ambiguity: true,
+            ..(*primary_binding).clone()
+        })
+    }
+
     // Use `f` to mutate the resolution of the name in the module.
     // If the resolution becomes a success, define it in the module's glob importers.
-    fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T
+    fn update_resolution<T, F>(
+        &mut self,
+        module: Module<'a>,
+        key: BindingKey,
+        warn_ambiguity: bool,
+        f: F,
+    ) -> T
     where
         F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T,
     {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
-        let (binding, t) = {
+        let (binding, t, warn_ambiguity) = {
             let resolution = &mut *self.resolution(module, key).borrow_mut();
             let old_binding = resolution.binding();
 
             let t = f(self, resolution);
 
-            if old_binding.is_none() && let Some(binding) = resolution.binding() {
-                (binding, t)
+            if let Some(binding) = resolution.binding() && old_binding != Some(binding) {
+                (binding, t, warn_ambiguity || old_binding.is_some())
             } else {
                 return t;
             }
         };
 
-        // Define `binding` in `module`s glob importers.
-        for import in module.glob_importers.borrow_mut().iter() {
+        let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else {
+            return t;
+        };
+
+        // Define or update `binding` in `module`s glob importers.
+        for import in glob_importers.iter() {
             let mut ident = key.ident;
             let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) {
                 Some(Some(def)) => self.expn_def_scope(def),
@@ -406,7 +459,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if self.is_accessible_from(binding.vis, scope) {
                 let imported_binding = self.import(binding, *import);
                 let key = BindingKey { ident, ..key };
-                let _ = self.try_define(import.parent_scope.module, key, imported_binding);
+                let _ = self.try_define(
+                    import.parent_scope.module,
+                    key,
+                    imported_binding,
+                    warn_ambiguity,
+                );
             }
         }
 
@@ -425,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let dummy_binding = self.import(dummy_binding, import);
             self.per_ns(|this, ns| {
                 let key = BindingKey::new(target, ns);
-                let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
+                let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false);
             });
             self.record_use(target, dummy_binding, false);
         } else if import.imported_module.get().is_none() {
@@ -700,7 +758,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             Segment::names_to_string(&import.module_path),
             module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()),
         );
-
         let module = if let Some(module) = import.imported_module.get() {
             module
         } else {
@@ -773,7 +830,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 .emit();
                         }
                         let key = BindingKey::new(target, ns);
-                        this.update_resolution(parent, key, |_, resolution| {
+                        this.update_resolution(parent, key, false, |_, resolution| {
                             resolution.single_imports.remove(&import);
                         });
                     }
@@ -989,14 +1046,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             initial_binding.res()
                         });
                         let res = binding.res();
+                        let has_ambiguity_error = this
+                            .ambiguity_errors
+                            .iter()
+                            .filter(|error| !error.warning)
+                            .next()
+                            .is_some();
+                        if res == Res::Err || has_ambiguity_error {
+                            this.tcx
+                                .sess
+                                .delay_span_bug(import.span, "some error happened for an import");
+                            return;
+                        }
                         if let Ok(initial_res) = initial_res {
-                            if res != initial_res && this.ambiguity_errors.is_empty() {
+                            if res != initial_res {
                                 span_bug!(import.span, "inconsistent resolution for an import");
                             }
-                        } else if res != Res::Err
-                            && this.ambiguity_errors.is_empty()
-                            && this.privacy_errors.is_empty()
-                        {
+                        } else if this.privacy_errors.is_empty() {
                             this.tcx
                                 .sess
                                 .create_err(CannotDetermineImportResolution { span: import.span })
@@ -1087,18 +1153,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     ModuleOrUniformRoot::Module(module) => {
                         let module_str = module_to_string(module);
                         if let Some(module_str) = module_str {
-                            format!("no `{}` in `{}`", ident, module_str)
+                            format!("no `{ident}` in `{module_str}`")
                         } else {
-                            format!("no `{}` in the root", ident)
+                            format!("no `{ident}` in the root")
                         }
                     }
                     _ => {
                         if !ident.is_path_segment_keyword() {
-                            format!("no external crate `{}`", ident)
+                            format!("no external crate `{ident}`")
                         } else {
                             // HACK(eddyb) this shows up for `self` & `super`, which
                             // should work instead - for now keep the same error message.
-                            format!("no `{}` in the root", ident)
+                            format!("no `{ident}` in the root")
                         }
                     }
                 };
@@ -1146,10 +1212,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let (ns, binding) = reexport_error.unwrap();
             if pub_use_of_private_extern_crate_hack(import, binding) {
                 let msg = format!(
-                    "extern crate `{}` is private, and cannot be \
+                    "extern crate `{ident}` is private, and cannot be \
                                    re-exported (error E0365), consider declaring with \
-                                   `pub`",
-                    ident
+                                   `pub`"
                 );
                 self.lint_buffer.buffer_lint(
                     PUB_USE_OF_PRIVATE_EXTERN_CRATE,
@@ -1289,7 +1354,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 UNUSED_IMPORTS,
                 id,
                 import.span,
-                format!("the item `{}` is imported redundantly", ident),
+                format!("the item `{ident}` is imported redundantly"),
                 BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
             );
         }
@@ -1335,7 +1400,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             };
             if self.is_accessible_from(binding.vis, scope) {
                 let imported_binding = self.import(binding, import);
-                let _ = self.try_define(import.parent_scope.module, key, imported_binding);
+                let warn_ambiguity = self
+                    .resolution(import.parent_scope.module, key)
+                    .borrow()
+                    .binding()
+                    .is_some_and(|binding| binding.is_warn_ambiguity());
+                let _ = self.try_define(
+                    import.parent_scope.module,
+                    key,
+                    imported_binding,
+                    warn_ambiguity,
+                );
             }
         }
 
@@ -1354,7 +1429,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             module.for_each_child(self, |this, ident, _, binding| {
                 let res = binding.res().expect_non_local();
-                if res != def::Res::Err && !binding.is_ambiguity() {
+                let error_ambiguity = binding.is_ambiguity() && !binding.warn_ambiguity;
+                if res != def::Res::Err && !error_ambiguity {
                     let mut reexport_chain = SmallVec::new();
                     let mut next_binding = binding;
                     while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 05128a51016..0e9d74480a9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -337,6 +337,7 @@ enum LifetimeBinderKind {
     PolyTrait,
     WhereBound,
     Item,
+    ConstItem,
     Function,
     Closure,
     ImplBlock,
@@ -349,7 +350,7 @@ impl LifetimeBinderKind {
             BareFnType => "type",
             PolyTrait => "bound",
             WhereBound => "bound",
-            Item => "item",
+            Item | ConstItem => "item",
             ImplBlock => "impl block",
             Function => "function",
             Closure => "closure",
@@ -549,6 +550,7 @@ enum MaybeExported<'a> {
     Ok(NodeId),
     Impl(Option<DefId>),
     ImplItem(Result<DefId, &'a Visibility>),
+    NestedUse(&'a Visibility),
 }
 
 impl MaybeExported<'_> {
@@ -559,7 +561,9 @@ impl MaybeExported<'_> {
                 trait_def_id.as_local()
             }
             MaybeExported::Impl(None) => return true,
-            MaybeExported::ImplItem(Err(vis)) => return vis.kind.is_pub(),
+            MaybeExported::ImplItem(Err(vis)) | MaybeExported::NestedUse(vis) => {
+                return vis.kind.is_pub();
+            }
         };
         def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
     }
@@ -1913,10 +1917,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         candidate: LifetimeElisionCandidate,
     ) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
-            panic!(
-                "lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
-                id, prev_res, res
-            )
+            panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
         }
         match res {
             LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
@@ -1932,8 +1933,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
             panic!(
-                "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
-                id, prev_res, res
+                "lifetime parameter {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)"
             )
         }
     }
@@ -2284,7 +2284,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     fn resolve_item(&mut self, item: &'ast Item) {
         let mod_inner_docs =
             matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs);
-        if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..)) {
+        if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..) | ItemKind::Use(..)) {
             self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
         }
 
@@ -2401,33 +2401,53 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 });
             }
 
-            ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. })
-            | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => {
+            ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
                 self.with_static_rib(|this| {
                     this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
                         this.visit_ty(ty);
                     });
-                    this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+                    if let Some(expr) = expr {
+                        // We already forbid generic params because of the above item rib,
+                        // so it doesn't matter whether this is a trivial constant.
+                        this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static)));
+                    }
+                });
+            }
+
+            ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
+                self.with_generic_param_rib(
+                    &generics.params,
+                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    LifetimeRibKind::Generics {
+                        binder: item.id,
+                        kind: LifetimeBinderKind::ConstItem,
+                        span: generics.span,
+                    },
+                    |this| {
+                        this.visit_generics(generics);
+
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::Elided(LifetimeRes::Static),
+                            |this| this.visit_ty(ty),
+                        );
+
                         if let Some(expr) = expr {
-                            let constant_item_kind = match item.kind {
-                                ItemKind::Const(..) => ConstantItemKind::Const,
-                                ItemKind::Static(..) => ConstantItemKind::Static,
-                                _ => unreachable!(),
-                            };
-                            // We already forbid generic params because of the above item rib,
-                            // so it doesn't matter whether this is a trivial constant.
-                            this.with_constant_rib(
-                                IsRepeatExpr::No,
-                                ConstantHasGenerics::Yes,
-                                Some((item.ident, constant_item_kind)),
-                                |this| this.visit_expr(expr),
+                            this.resolve_const_body(
+                                expr,
+                                Some((item.ident, ConstantItemKind::Const)),
                             );
                         }
-                    });
-                });
+                    },
+                );
             }
 
             ItemKind::Use(ref use_tree) => {
+                let maybe_exported = match use_tree.kind {
+                    UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id),
+                    UseTreeKind::Nested(_) => MaybeExported::NestedUse(&item.vis),
+                };
+                self.resolve_doc_links(&item.attrs, maybe_exported);
+
                 self.future_proof_import(use_tree);
             }
 
@@ -2569,7 +2589,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let res = match kind {
                 RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
                 RibKind::Normal => {
-                    if self.r.tcx.sess.features_untracked().non_lifetime_binders {
+                    if self.r.tcx.features().non_lifetime_binders {
                         Res::Def(def_kind, def_id.to_def_id())
                     } else {
                         Res::Err
@@ -2691,28 +2711,31 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         for item in trait_items {
             self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
             match &item.kind {
-                AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
-                    self.visit_ty(ty);
-                    // Only impose the restrictions of `ConstRibKind` for an
-                    // actual constant expression in a provided default.
-                    if let Some(expr) = expr {
-                        // We allow arbitrary const expressions inside of associated consts,
-                        // even if they are potentially not const evaluatable.
-                        //
-                        // Type parameters can already be used and as associated consts are
-                        // not used as part of the type system, this is far less surprising.
-                        self.with_lifetime_rib(
-                            LifetimeRibKind::Elided(LifetimeRes::Infer),
-                            |this| {
-                                this.with_constant_rib(
-                                    IsRepeatExpr::No,
-                                    ConstantHasGenerics::Yes,
-                                    None,
-                                    |this| this.visit_expr(expr),
-                                )
-                            },
-                        );
-                    }
+                AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
+                    self.with_generic_param_rib(
+                        &generics.params,
+                        RibKind::AssocItem,
+                        LifetimeRibKind::Generics {
+                            binder: item.id,
+                            span: generics.span,
+                            kind: LifetimeBinderKind::ConstItem,
+                        },
+                        |this| {
+                            this.visit_generics(generics);
+                            this.visit_ty(ty);
+
+                            // Only impose the restrictions of `ConstRibKind` for an
+                            // actual constant expression in a provided default.
+                            if let Some(expr) = expr {
+                                // We allow arbitrary const expressions inside of associated consts,
+                                // even if they are potentially not const evaluatable.
+                                //
+                                // Type parameters can already be used and as associated consts are
+                                // not used as part of the type system, this is far less surprising.
+                                this.resolve_const_body(expr, None);
+                            }
+                        },
+                    );
                 }
                 AssocItemKind::Fn(box Fn { generics, .. }) => {
                     walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
@@ -2867,36 +2890,42 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         use crate::ResolutionError::*;
         self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
         match &item.kind {
-            AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
+            AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
                 debug!("resolve_implementation AssocItemKind::Const");
-                // If this is a trait impl, ensure the const
-                // exists in trait
-                self.check_trait_item(
-                    item.id,
-                    item.ident,
-                    &item.kind,
-                    ValueNS,
-                    item.span,
-                    seen_trait_items,
-                    |i, s, c| ConstNotMemberOfTrait(i, s, c),
-                );
 
-                self.visit_ty(ty);
-                if let Some(expr) = expr {
-                    // We allow arbitrary const expressions inside of associated consts,
-                    // even if they are potentially not const evaluatable.
-                    //
-                    // Type parameters can already be used and as associated consts are
-                    // not used as part of the type system, this is far less surprising.
-                    self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
-                        this.with_constant_rib(
-                            IsRepeatExpr::No,
-                            ConstantHasGenerics::Yes,
-                            None,
-                            |this| this.visit_expr(expr),
-                        )
-                    });
-                }
+                self.with_generic_param_rib(
+                    &generics.params,
+                    RibKind::AssocItem,
+                    LifetimeRibKind::Generics {
+                        binder: item.id,
+                        span: generics.span,
+                        kind: LifetimeBinderKind::ConstItem,
+                    },
+                    |this| {
+                        // If this is a trait impl, ensure the const
+                        // exists in trait
+                        this.check_trait_item(
+                            item.id,
+                            item.ident,
+                            &item.kind,
+                            ValueNS,
+                            item.span,
+                            seen_trait_items,
+                            |i, s, c| ConstNotMemberOfTrait(i, s, c),
+                        );
+
+                        this.visit_generics(generics);
+                        this.visit_ty(ty);
+                        if let Some(expr) = expr {
+                            // We allow arbitrary const expressions inside of associated consts,
+                            // even if they are potentially not const evaluatable.
+                            //
+                            // Type parameters can already be used and as associated consts are
+                            // not used as part of the type system, this is far less surprising.
+                            this.resolve_const_body(expr, None);
+                        }
+                    },
+                );
             }
             AssocItemKind::Fn(box Fn { generics, .. }) => {
                 debug!("resolve_implementation AssocItemKind::Fn");
@@ -3054,6 +3083,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         );
     }
 
+    fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
+        self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+            this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
+                this.visit_expr(expr)
+            });
+        })
+    }
+
     fn resolve_params(&mut self, params: &'ast [Param]) {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
         self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
@@ -4439,6 +4476,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
     fn visit_item(&mut self, item: &'ast Item) {
         match &item.kind {
             ItemKind::TyAlias(box TyAlias { ref generics, .. })
+            | ItemKind::Const(box ConstItem { ref generics, .. })
             | ItemKind::Fn(box Fn { ref generics, .. })
             | ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
@@ -4458,7 +4496,6 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
             ItemKind::Mod(..)
             | ItemKind::ForeignMod(..)
             | ItemKind::Static(..)
-            | ItemKind::Const(..)
             | ItemKind::Use(..)
             | ItemKind::ExternCrate(..)
             | ItemKind::MacroDef(..)
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 753a1adc66d..974580f815b 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -585,13 +585,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     let others = match enum_candidates.len() {
                         1 => String::new(),
                         2 => " and 1 other".to_owned(),
-                        n => format!(" and {} others", n),
+                        n => format!(" and {n} others"),
                     };
                     format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
                 } else {
                     String::new()
                 };
-                let msg = format!("{}try using the variant's enum", preamble);
+                let msg = format!("{preamble}try using the variant's enum");
 
                 err.span_suggestions(
                     span,
@@ -696,7 +696,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     ident.name == path[0].ident.name {
                     err.span_help(
                         ident.span,
-                        format!("the binding `{}` is available in a different scope in the same function", path_str),
+                        format!("the binding `{path_str}` is available in a different scope in the same function"),
                     );
                     return (true, candidates);
                 }
@@ -858,7 +858,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 for label_rib in &self.label_ribs {
                     for (label_ident, node_id) in &label_rib.bindings {
                         let ident = path.last().unwrap().ident;
-                        if format!("'{}", ident) == label_ident.to_string() {
+                        if format!("'{ident}") == label_ident.to_string() {
                             err.span_label(label_ident.span, "a label with a similar name exists");
                             if let PathSource::Expr(Some(Expr {
                                 kind: ExprKind::Break(None, Some(_)),
@@ -983,7 +983,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 if let Some(ident) = fn_kind.ident() {
                     err.span_label(
                         ident.span,
-                        format!("this function {} have a `self` parameter", doesnt),
+                        format!("this function {doesnt} have a `self` parameter"),
                     );
                 }
             }
@@ -1164,7 +1164,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         };
                         err.span_suggestion_verbose(
                             *where_span,
-                            format!("constrain the associated type to `{}`", ident),
+                            format!("constrain the associated type to `{ident}`"),
                             where_bound_predicate_to_string(&new_where_bound_predicate),
                             Applicability::MaybeIncorrect,
                         );
@@ -1338,8 +1338,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             span, // Note the parentheses surrounding the suggestion below
                             format!(
                                 "you might want to surround a struct literal with parentheses: \
-                                 `({} {{ /* fields */ }})`?",
-                                path_str
+                                 `({path_str} {{ /* fields */ }})`?"
                             ),
                         );
                     }
@@ -1373,7 +1372,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                                     .map(|(idx, new)| (new, old_fields.get(idx)))
                                     .map(|(new, old)| {
                                         let new = new.to_ident_string();
-                                        if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new }
+                                        if let Some(Some(old)) = old && new != *old { format!("{new}: {old}") } else { new }
                                     })
                                     .collect::<Vec<String>>()
                             } else {
@@ -1390,7 +1389,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     };
                     err.span_suggestion(
                         span,
-                        format!("use struct {} syntax instead", descr),
+                        format!("use struct {descr} syntax instead"),
                         format!("{path_str} {{{pad}{fields}{pad}}}"),
                         applicability,
                     );
@@ -1584,7 +1583,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 err.span_suggestion(
                     span,
                     "use the tuple variant pattern syntax instead",
-                    format!("{}({})", path_str, fields),
+                    format!("{path_str}({fields})"),
                     Applicability::HasPlaceholders,
                 );
             }
@@ -1994,9 +1993,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
             if !suggestable_variants.is_empty() {
                 let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
-                    format!("try {} the enum's variant", source_msg)
+                    format!("try {source_msg} the enum's variant")
                 } else {
-                    format!("try {} one of the enum's variants", source_msg)
+                    format!("try {source_msg} one of the enum's variants")
                 };
 
                 err.span_suggestions(
@@ -2009,19 +2008,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
             // If the enum has no tuple variants..
             if non_suggestable_variant_count == variants.len() {
-                err.help(format!("the enum has no tuple variants {}", source_msg));
+                err.help(format!("the enum has no tuple variants {source_msg}"));
             }
 
             // If there are also non-tuple variants..
             if non_suggestable_variant_count == 1 {
-                err.help(format!(
-                    "you might have meant {} the enum's non-tuple variant",
-                    source_msg
-                ));
+                err.help(format!("you might have meant {source_msg} the enum's non-tuple variant"));
             } else if non_suggestable_variant_count >= 1 {
                 err.help(format!(
-                    "you might have meant {} one of the enum's non-tuple variants",
-                    source_msg
+                    "you might have meant {source_msg} one of the enum's non-tuple variants"
                 ));
             }
         } else {
@@ -2041,7 +2036,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
                 .map(|(variant, kind)| match kind {
                     CtorKind::Const => variant,
-                    CtorKind::Fn => format!("({}())", variant),
+                    CtorKind::Fn => format!("({variant}())"),
                 })
                 .collect::<Vec<_>>();
             let no_suggestable_variant = suggestable_variants.is_empty();
@@ -2066,7 +2061,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
                 .filter_map(|(variant, kind)| match kind {
-                    CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
+                    CtorKind::Fn => Some(format!("({variant}(/* fields */))")),
                     _ => None,
                 })
                 .collect::<Vec<_>>();
@@ -2348,13 +2343,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             let mut should_continue = true;
             match rib.kind {
                 LifetimeRibKind::Generics { binder: _, span, kind } => {
+                    // Avoid suggesting placing lifetime parameters on constant items unless the relevant
+                    // feature is enabled. Suggest the parent item as a possible location if applicable.
+                    if let LifetimeBinderKind::ConstItem = kind
+                        && !self.r.tcx().features().generic_const_items
+                    {
+                        continue;
+                    }
+
                     if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
                         suggest_note = false; // Avoid displaying the same help multiple times.
                         err.span_label(
                             span,
                             format!(
-                                "lifetime `{}` is missing in item created through this procedural macro",
-                                name,
+                                "lifetime `{name}` is missing in item created through this procedural macro",
                             ),
                         );
                         continue;
@@ -2398,7 +2400,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         );
                     } else if let Some(name) = name {
                         let message =
-                            Cow::from(format!("consider introducing lifetime `{}` here", name));
+                            Cow::from(format!("consider introducing lifetime `{name}` here"));
                         should_continue = suggest(err, false, span, message, sugg);
                     } else {
                         let message = Cow::from("consider introducing a named lifetime parameter");
@@ -2542,7 +2544,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
 
                 let help_name = if let Some(ident) = ident {
-                    format!("`{}`", ident)
+                    format!("`{ident}`")
                 } else {
                     format!("argument {}", index + 1)
                 };
@@ -2550,7 +2552,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 if lifetime_count == 1 {
                     m.push_str(&help_name[..])
                 } else {
-                    m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..])
+                    m.push_str(&format!("one of {help_name}'s {lifetime_count} lifetimes")[..])
                 }
             }
 
@@ -2580,14 +2582,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             } else if num_params == 1 {
                 err.help(format!(
                     "this function's return type contains a borrowed value, \
-                 but the signature does not say which {} it is borrowed from",
-                    m
+                 but the signature does not say which {m} it is borrowed from"
                 ));
             } else {
                 err.help(format!(
                     "this function's return type contains a borrowed value, \
-                 but the signature does not say whether it is borrowed from {}",
-                    m
+                 but the signature does not say whether it is borrowed from {m}"
                 ));
             }
         }
@@ -2606,7 +2606,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
             MissingLifetimeKind::Ampersand => {
                 debug_assert_eq!(lt.count, 1);
-                (lt.span.shrink_to_hi(), format!("{} ", existing_name))
+                (lt.span.shrink_to_hi(), format!("{existing_name} "))
             }
             MissingLifetimeKind::Comma => {
                 let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
@@ -2653,7 +2653,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
             1 => {
                 err.multipart_suggestion_verbose(
-                    format!("consider using the `{}` lifetime", existing_name),
+                    format!("consider using the `{existing_name}` lifetime"),
                     spans_suggs,
                     Applicability::MaybeIncorrect,
                 );
@@ -2770,9 +2770,9 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident
     let shadower = shadower.span;
     let mut err = sess.struct_span_warn(
         shadower,
-        format!("label name `{}` shadows a label name that is already in scope", name),
+        format!("label name `{name}` shadows a label name that is already in scope"),
     );
     err.span_label(orig, "first declared here");
-    err.span_label(shadower, format!("label `{}` already in scope", name));
+    err.span_label(shadower, format!("label `{name}` already in scope"));
     err.emit();
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index faa672db59c..da5e92a075a 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -658,6 +658,7 @@ impl<'a> fmt::Debug for Module<'a> {
 struct NameBindingData<'a> {
     kind: NameBindingKind<'a>,
     ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>,
+    warn_ambiguity: bool,
     expansion: LocalExpnId,
     span: Span,
     vis: ty::Visibility<DefId>,
@@ -767,6 +768,7 @@ struct AmbiguityError<'a> {
     b2: NameBinding<'a>,
     misc1: AmbiguityErrorMisc,
     misc2: AmbiguityErrorMisc,
+    warning: bool,
 }
 
 impl<'a> NameBindingData<'a> {
@@ -794,6 +796,14 @@ impl<'a> NameBindingData<'a> {
             }
     }
 
+    fn is_warn_ambiguity(&self) -> bool {
+        self.warn_ambiguity
+            || match self.kind {
+                NameBindingKind::Import { binding, .. } => binding.is_warn_ambiguity(),
+                _ => false,
+            }
+    }
+
     fn is_possibly_imported_variant(&self) -> bool {
         match self.kind {
             NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
@@ -1158,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
-        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
     /// Adds a definition with a parent definition.
@@ -1322,6 +1332,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             dummy_binding: arenas.alloc_name_binding(NameBindingData {
                 kind: NameBindingKind::Res(Res::Err),
                 ambiguity: None,
+                warn_ambiguity: false,
                 expansion: LocalExpnId::ROOT,
                 span: DUMMY_SP,
                 vis: ty::Visibility::Public,
@@ -1685,6 +1696,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) {
+        self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity);
+    }
+
+    fn record_use_inner(
+        &mut self,
+        ident: Ident,
+        used_binding: NameBinding<'a>,
+        is_lexical_scope: bool,
+        warn_ambiguity: bool,
+    ) {
         if let Some((b2, kind)) = used_binding.ambiguity {
             let ambiguity_error = AmbiguityError {
                 kind,
@@ -1693,9 +1714,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 b2,
                 misc1: AmbiguityErrorMisc::None,
                 misc2: AmbiguityErrorMisc::None,
+                warning: warn_ambiguity,
             };
             if !self.matches_previous_ambiguity_error(&ambiguity_error) {
-                // avoid duplicated span information to be emitt out
+                // avoid duplicated span information to be emit out
                 self.ambiguity_errors.push(ambiguity_error);
             }
         }
@@ -1715,7 +1737,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 self.used_imports.insert(id);
             }
             self.add_to_glob_map(import, ident);
-            self.record_use(ident, binding, false);
+            self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity);
         }
     }
 
@@ -1812,7 +1834,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
         debug!("(recording res) recording {:?} for {}", resolution, node_id);
         if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
-            panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution);
+            panic!("path resolved multiple times ({prev_res:?} before, {resolution:?} now)");
         }
     }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d16b7902f60..614a29e7578 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -24,7 +24,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId};
 use rustc_middle::middle::stability;
 use rustc_middle::ty::RegisteredTools;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
+use rustc_session::lint::builtin::{
+    LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+};
 use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::feature_err;
@@ -140,9 +142,9 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
             }
         }
     }
-    // We implicitly add `rustfmt` and `clippy` to known tools,
+    // We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools,
     // but it's not an error to register them explicitly.
-    let predefined_tools = [sym::clippy, sym::rustfmt];
+    let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic];
     registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
     registered_tools
 }
@@ -205,7 +207,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
             self.tcx
                 .sess
                 .diagnostic()
-                .bug(format!("built-in macro `{}` was already registered", name));
+                .bug(format!("built-in macro `{name}` was already registered"));
         }
     }
 
@@ -568,7 +570,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             let mut err = self.tcx.sess.create_err(err);
-            err.span_label(path.span, format!("not {} {}", article, expected));
+            err.span_label(path.span, format!("not {article} {expected}"));
 
             err.emit();
 
@@ -576,10 +578,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         // We are trying to avoid reporting this error if other related errors were reported.
-        if res != Res::Err
-            && inner_attr
-            && !self.tcx.sess.features_untracked().custom_inner_attributes
-        {
+        if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes {
             let msg = match res {
                 Res::Def(..) => "inner macro attributes are unstable",
                 Res::NonMacroAttr(..) => "custom inner attributes are unstable",
@@ -598,6 +597,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         }
 
+        if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
+            && path.segments.len() >= 2
+            && path.segments[0].ident.name == sym::diagnostic
+        {
+            self.tcx.sess.parse_sess.buffer_lint(
+                UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+                path.segments[1].span(),
+                node_id,
+                "unknown diagnostic attribute",
+            );
+        }
+
         Ok((ext, res))
     }
 
@@ -895,7 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
                 self.tcx.sess.span_err(
                     ident.span,
-                    format!("name `{}` is reserved in attribute namespace", ident),
+                    format!("name `{ident}` is reserved in attribute namespace"),
                 );
             }
         }