about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs5
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs54
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs3
-rw-r--r--compiler/rustc_resolve/src/ident.rs14
-rw-r--r--compiler/rustc_resolve/src/imports.rs40
-rw-r--r--compiler/rustc_resolve/src/late.rs87
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs244
-rw-r--r--compiler/rustc_resolve/src/lib.rs19
-rw-r--r--compiler/rustc_resolve/src/macros.rs62
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs4
11 files changed, 338 insertions, 196 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index a18109574fe..0407db528af 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -981,7 +981,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 | DefKind::GlobalAsm
                 | DefKind::Closure
                 | DefKind::Impl { .. }
-                | DefKind::Generator,
+                | DefKind::Coroutine,
                 _,
             )
             | Res::Local(..)
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 7dbbd4c34ea..352bf98d01f 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -59,7 +59,6 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
     item_span: Span,
-    base_use_is_pub: bool,
 }
 
 struct ExternCrateToLint {
@@ -146,7 +145,6 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             // because this means that they were generated in some fashion by the
             // compiler and we don't need to consider them.
             ast::ItemKind::Use(..) if item.span.is_dummy() => return,
-            ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(),
             ast::ItemKind::ExternCrate(orig_name) => {
                 self.extern_crate_items.push(ExternCrateToLint {
                     id: item.id,
@@ -173,7 +171,7 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             self.base_use_tree = Some(use_tree);
         }
 
-        if self.base_use_is_pub {
+        if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) {
             self.check_import_as_underscore(use_tree, id);
             return;
         }
@@ -332,7 +330,6 @@ impl Resolver<'_, '_> {
             base_use_tree: None,
             base_id: ast::DUMMY_NODE_ID,
             item_span: DUMMY_SP,
-            base_use_is_pub: false,
         };
         visit::walk_crate(&mut visitor, krate);
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 907a6b1c46c..4ad838e5aed 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -187,7 +187,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion_verbose(span, msg, sugg, appl);
                 err.emit();
-            } else if let [segment] = path.as_slice() && is_call {
+            } else if let [segment] = path.as_slice()
+                && is_call
+            {
                 err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
             } else {
                 err.emit();
@@ -1169,6 +1171,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     return;
                 }
 
+                if ident.name == kw::Underscore {
+                    return;
+                }
+
                 let child_accessible =
                     accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
 
@@ -1505,9 +1511,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 ),
             );
         }
+
+        let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+            && let Some(span) = suggestion.span
+            && let Some(candidate) = suggestion.candidate.as_str().strip_prefix("_")
+            && snippet == candidate
+        {
+            // When the suggested binding change would be from `x` to `_x`, suggest changing the
+            // original binding definition instead. (#60164)
+            (span, snippet, ", consider changing it")
+        } else {
+            (span, suggestion.candidate.to_string(), "")
+        };
         let msg = match suggestion.target {
             SuggestionTarget::SimilarlyNamed => format!(
-                "{} {} with a similar name exists",
+                "{} {} with a similar name exists{post}",
                 suggestion.res.article(),
                 suggestion.res.descr()
             ),
@@ -1515,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 format!("maybe you meant this {}", suggestion.res.descr())
             }
         };
-        err.span_suggestion(span, msg, suggestion.candidate, Applicability::MaybeIncorrect);
+        err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
         true
     }
 
@@ -1686,7 +1705,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             non_exhaustive = Some(attr.span);
         } else if let Some(span) = ctor_fields_span {
             err.span_label(span, "a constructor is private if any of the fields is private");
-            if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) {
+            if let Res::Def(_, d) = res
+                && let Some(fields) = self.field_visibility_spans.get(&d)
+            {
                 err.multipart_suggestion_verbose(
                     format!(
                         "consider making the field{} publicly accessible",
@@ -1735,7 +1756,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
             // Final step in the import chain, point out if the ADT is `non_exhaustive`
             // which is probably why this privacy violation occurred.
-            if next_binding.is_none() && let Some(span) = non_exhaustive {
+            if next_binding.is_none()
+                && let Some(span) = non_exhaustive
+            {
                 note_span.push_span_label(
                     span,
                     "cannot be constructed because it is `#[non_exhaustive]`",
@@ -1842,7 +1865,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         parent_scope,
                         None,
                         ignore_binding,
-                    ).ok()
+                    )
+                    .ok()
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
                 {
@@ -1866,7 +1890,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         None,
                         false,
                         ignore_binding,
-                    ).ok()
+                    )
+                    .ok()
                 };
                 if let Some(binding) = binding {
                     let mut found = |what| {
@@ -2228,7 +2253,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                 // Add the import to the start, with a `{` if required.
                 let start_point = source_map.start_point(after_crate_name);
-                if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) {
+                if is_definitely_crate
+                    && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
+                {
                     corrections.push((
                         start_point,
                         if has_nested {
@@ -2243,7 +2270,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                     // Add a `};` to the end if nested, matching the `{` added at the start.
                     if !has_nested {
-                        corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
+                        corrections
+                            .push((source_map.end_point(after_crate_name), "};".to_string()));
                     }
                 } else {
                     // If the root import is module-relative, add the import separately
@@ -2582,7 +2610,13 @@ fn show_candidates(
             for candidate in &mut accessible_path_strings {
                 // produce an additional newline to separate the new use statement
                 // from the directly following item.
-                let additional_newline = if let FoundUse::No = found_use && let DiagnosticMode::Normal = mode { "\n" } else { "" };
+                let additional_newline = if let FoundUse::No = found_use
+                    && let DiagnosticMode::Normal = mode
+                {
+                    "\n"
+                } else {
+                    ""
+                };
                 candidate.0 =
                     format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0);
             }
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 46f5df5ca6f..4477b967283 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -147,7 +147,8 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
                     warn_ambiguity |= nested_binding.warn_ambiguity;
                 }
                 if !is_ambiguity(binding, warn_ambiguity)
-                    && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+                    && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
+                {
                     self.update_def(def_id, binding.vis.expect_local(), parent_id);
                 }
             }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 54388f80f15..f2fd4b0bf60 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -896,7 +896,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT {
                 if let NameBindingKind::Import { import, .. } = binding.kind
-                    && matches!(import.kind, ImportKind::MacroExport) {
+                    && matches!(import.kind, ImportKind::MacroExport)
+                {
                     self.macro_expanded_macro_export_errors.insert((path_span, binding.span));
                 }
             }
@@ -928,9 +929,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if !self.is_accessible_from(import_vis, parent_scope.module) {
                 continue;
             }
-            if let Some(ignored) = ignore_binding &&
-                let NameBindingKind::Import { import, .. } = ignored.kind &&
-                import == *single_import {
+            if let Some(ignored) = ignore_binding
+                && let NameBindingKind::Import { import, .. } = ignored.kind
+                && import == *single_import
+            {
                 // Ignore not just the binding itself, but if it has a shadowed_glob,
                 // ignore that, too, because this loop is supposed to only process
                 // named imports.
@@ -1440,7 +1442,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     ignore_binding,
                 )
-            } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns {
+            } else if let Some(ribs) = ribs
+                && let Some(TypeNS | ValueNS) = opt_ns
+            {
                 match self.resolve_ident_in_lexical_scope(
                     ident,
                     ns,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d271519a8a3..b34790a925e 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -313,26 +313,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     (true, true) => {
                         // 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: old_import, .. } =
+                                old_binding.kind
                             && let NameBindingKind::Import { import, .. } = binding.kind
-                            && old_import == import {
+                            && 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.
                             resolution.binding = Some(binding);
                         } else if res != old_binding.res() {
                             let binding = if warn_ambiguity {
-                                this.warn_ambiguity(
-                                    AmbiguityKind::GlobVsGlob,
-                                    old_binding,
-                                    binding,
-                                )
+                                this.warn_ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding)
                             } else {
-                                this.ambiguity(
-                                    AmbiguityKind::GlobVsGlob,
-                                    old_binding,
-                                    binding,
-                                )
+                                this.ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding)
                             };
                             resolution.binding = Some(binding);
                         } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
@@ -434,7 +428,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             let t = f(self, resolution);
 
-            if let Some(binding) = resolution.binding() && old_binding != Some(binding) {
+            if let Some(binding) = resolution.binding()
+                && old_binding != Some(binding)
+            {
                 (binding, t, warn_ambiguity || old_binding.is_some())
             } else {
                 return t;
@@ -637,7 +633,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                         if binding.res() != Res::Err
                             && glob_binding.res() != Res::Err
-                            && let NameBindingKind::Import { import: glob_import, .. } = glob_binding.kind
+                            && let NameBindingKind::Import { import: glob_import, .. } =
+                                glob_binding.kind
                             && let Some(binding_id) = binding_id
                             && let Some(glob_import_id) = glob_import.id()
                             && let glob_import_def_id = self.local_def_id(glob_import_id)
@@ -738,11 +735,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             match &import.kind {
                 ImportKind::Single { source, .. } => {
                     if let Some(ModuleOrUniformRoot::Module(module)) = import.imported_module.get()
-                     && let Some(module) = module.opt_def_id()
+                        && let Some(module) = module.opt_def_id()
                     {
                         self.find_cfg_stripped(&mut diag, &source.name, module)
                     }
-                },
+                }
                 _ => {}
             }
         }
@@ -989,10 +986,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         }
                     }
                     if !is_prelude
-                    && let Some(max_vis) = max_vis.get()
-                    && !max_vis.is_at_least(import.expect_vis(), self.tcx)
+                        && let Some(max_vis) = max_vis.get()
+                        && !max_vis.is_at_least(import.expect_vis(), self.tcx)
                     {
-                        self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, fluent::resolve_glob_import_doesnt_reexport);
+                        self.lint_buffer.buffer_lint(
+                            UNUSED_IMPORTS,
+                            id,
+                            import.span,
+                            fluent::resolve_glob_import_doesnt_reexport,
+                        );
                     }
                     return None;
                 }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c3c43346ed8..42ca407cddf 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -41,9 +41,6 @@ type Res = def::Res<NodeId>;
 
 type IdentMap<T> = FxHashMap<Ident, T>;
 
-/// Map from the name in a pattern to its binding mode.
-type BindingMap = IdentMap<BindingInfo>;
-
 use diagnostics::{
     ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
 };
@@ -739,7 +736,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                 // Check whether we should interpret this as a bare trait object.
                 if qself.is_none()
                     && let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
-                    && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
+                    && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) =
+                        partial_res.full_res()
                 {
                     // This path is actually a bare trait object. In case of a bare `Fn`-trait
                     // object with anonymous lifetimes, we need this rib to correctly place the
@@ -2049,7 +2047,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 if lifetime_count != 0 {
                     parameter_info.push(ElisionFnParameter {
                         index,
-                        ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
+                        ident: if let Some(pat) = pat
+                            && let PatKind::Ident(_, ident, _) = pat.kind
+                        {
                             Some(ident)
                         } else {
                             None
@@ -2143,7 +2143,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
             fn visit_ty(&mut self, ty: &'a Ty) {
                 trace!("SelfVisitor considering ty={:?}", ty);
-                if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
+                if let TyKind::Ref(lt, ref mt) = ty.kind
+                    && self.is_self_ty(&mt.ty)
+                {
                     let lt_id = if let Some(lt) = lt {
                         lt.id
                     } else {
@@ -3164,8 +3166,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     /// this is done hygienically. This could arise for a macro
     /// that expands into an or-pattern where one 'x' was from the
     /// user and one 'x' came from the macro.
-    fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
-        let mut binding_map = FxHashMap::default();
+    fn binding_mode_map(&mut self, pat: &Pat) -> FxIndexMap<Ident, BindingInfo> {
+        let mut binding_map = FxIndexMap::default();
 
         pat.walk(&mut |pat| {
             match pat.kind {
@@ -3200,22 +3202,28 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
     /// Checks that all of the arms in an or-pattern have exactly the
     /// same set of bindings, with the same binding modes for each.
-    fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<BindingMap> {
-        let mut missing_vars = FxHashMap::default();
-        let mut inconsistent_vars = FxHashMap::default();
+    fn check_consistent_bindings(
+        &mut self,
+        pats: &[P<Pat>],
+    ) -> Vec<FxIndexMap<Ident, BindingInfo>> {
+        // pats is consistent.
+        let mut missing_vars = FxIndexMap::default();
+        let mut inconsistent_vars = FxIndexMap::default();
 
         // 1) Compute the binding maps of all arms.
         let maps = pats.iter().map(|pat| self.binding_mode_map(pat)).collect::<Vec<_>>();
 
         // 2) Record any missing bindings or binding mode inconsistencies.
-        for (map_outer, pat_outer) in pats.iter().enumerate().map(|(idx, pat)| (&maps[idx], pat)) {
+        for (map_outer, pat_outer) in maps.iter().zip(pats.iter()) {
             // Check against all arms except for the same pattern which is always self-consistent.
-            let inners = pats
+            let inners = maps
                 .iter()
-                .enumerate()
+                .zip(pats.iter())
                 .filter(|(_, pat)| pat.id != pat_outer.id)
-                .flat_map(|(idx, _)| maps[idx].iter())
-                .map(|(key, binding)| (key.name, map_outer.get(&key), binding));
+                .flat_map(|(map, _)| map)
+                .map(|(key, binding)| (key.name, map_outer.get(key), binding));
+
+            let inners = inners.collect::<Vec<_>>();
 
             for (name, info, &binding_inner) in inners {
                 match info {
@@ -3244,10 +3252,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         }
 
         // 3) Report all missing variables we found.
-        let mut missing_vars = missing_vars.into_iter().collect::<Vec<_>>();
-        missing_vars.sort_by_key(|&(sym, ref _err)| sym);
-
-        for (name, mut v) in missing_vars.into_iter() {
+        for (name, mut v) in missing_vars {
             if inconsistent_vars.contains_key(&name) {
                 v.could_be_path = false;
             }
@@ -3258,10 +3263,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         }
 
         // 4) Report all inconsistencies in binding modes we found.
-        let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
-        inconsistent_vars.sort();
         for (name, v) in inconsistent_vars {
-            self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
+            self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(name, v.1));
         }
 
         // 5) Finally bubble up all the binding maps.
@@ -3604,7 +3607,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                         sugg.to_string(),
                         Applicability::MaybeIncorrect,
                     ))
-                } else if res.is_none() && let PathSource::Type | PathSource::Expr(_) = source {
+                } else if res.is_none()
+                    && let PathSource::Type | PathSource::Expr(_) = source
+                {
                     this.suggest_adding_generic_parameter(path, source)
                 } else {
                     None
@@ -4006,7 +4011,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     "unnecessary qualification",
                     lint::BuiltinLintDiagnostics::UnusedQualifications {
                         removal_span: finalize.path_span.until(last_segment.ident.span),
-                    }
+                    },
                 )
             }
         }
@@ -4059,13 +4064,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             (block.could_be_bare_literal, &block.stmts[..])
             && let ExprKind::Type(..) = expr.kind
         {
-            self.diagnostic_metadata.current_block_could_be_bare_struct_literal =
-            Some(block.span);
+            self.diagnostic_metadata.current_block_could_be_bare_struct_literal = Some(block.span);
         }
         // Descend into the block.
         for stmt in &block.stmts {
             if let StmtKind::Item(ref item) = stmt.kind
-                && let ItemKind::MacroDef(..) = item.kind {
+                && let ItemKind::MacroDef(..) = item.kind
+            {
                 num_macro_definition_ribs += 1;
                 let res = self.r.local_def_id(item.id).to_def_id();
                 self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res)));
@@ -4140,6 +4145,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         });
     }
 
+    fn resolve_expr_field(&mut self, f: &'ast ExprField, e: &'ast Expr) {
+        self.resolve_expr(&f.expr, Some(e));
+        self.visit_ident(f.ident);
+        walk_list!(self, visit_attribute, f.attrs.iter());
+    }
+
     fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
         // First, record candidate traits for this expression if it could
         // result in the invocation of a method call.
@@ -4155,7 +4166,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             ExprKind::Struct(ref se) => {
                 self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct);
-                visit::walk_expr(self, expr);
+                // This is the same as `visit::walk_expr(self, expr);`, but we want to pass the
+                // parent in for accurate suggestions when encountering `Foo { bar }` that should
+                // have been `Foo { bar: self.bar }`.
+                if let Some(qself) = &se.qself {
+                    self.visit_ty(&qself.ty);
+                }
+                self.visit_path(&se.path, expr.id);
+                walk_list!(self, resolve_expr_field, &se.fields, expr);
+                match &se.rest {
+                    StructRest::Base(expr) => self.visit_expr(expr),
+                    StructRest::Rest(_span) => {}
+                    StructRest::None => {}
+                }
             }
 
             ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
@@ -4403,7 +4426,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     && let Some(def_id) = res.opt_def_id()
                     && !def_id.is_local()
                     && self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
-                    && matches!(self.r.tcx.sess.opts.resolve_doc_links, ResolveDocLinks::ExportedMetadata) {
+                    && matches!(
+                        self.r.tcx.sess.opts.resolve_doc_links,
+                        ResolveDocLinks::ExportedMetadata
+                    )
+                {
                     // Encoding foreign def ids in proc macro crate metadata will ICE.
                     return None;
                 }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index adddc419daf..a5f8f61f3db 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -41,7 +41,7 @@ type Res = def::Res<ast::NodeId>;
 
 /// A field or associated item from self type suggested in case of resolution failure.
 enum AssocSuggestion {
-    Field,
+    Field(Span),
     MethodWithSelf { called: bool },
     AssocFn { called: bool },
     AssocType,
@@ -51,7 +51,7 @@ enum AssocSuggestion {
 impl AssocSuggestion {
     fn action(&self) -> &'static str {
         match self {
-            AssocSuggestion::Field => "use the available field",
+            AssocSuggestion::Field(_) => "use the available field",
             AssocSuggestion::MethodWithSelf { called: true } => {
                 "call the method with the fully-qualified path"
             }
@@ -215,7 +215,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
         } else {
             let mut span_label = None;
-            let item_span = path.last().unwrap().ident.span;
+            let item_ident = path.last().unwrap().ident;
+            let item_span = item_ident.span;
             let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
                 debug!(?self.diagnostic_metadata.current_impl_items);
                 debug!(?self.diagnostic_metadata.current_function);
@@ -228,12 +229,40 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         i.ident.name == item_str.name
                             // Don't suggest if the item is in Fn signature arguments (#112590).
                             && !sig.span.contains(item_span)
-                    })
-                {
+                    }) {
                     let sp = item_span.shrink_to_lo();
+
+                    // Account for `Foo { field }` when suggesting `self.field` so we result on
+                    // `Foo { field: self.field }`.
+                    let field = match source {
+                        PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {
+                            expr.fields.iter().find(|f| f.ident == item_ident)
+                        }
+                        _ => None,
+                    };
+                    let pre = if let Some(field) = field
+                        && field.is_shorthand
+                    {
+                        format!("{item_ident}: ")
+                    } else {
+                        String::new()
+                    };
+                    // Ensure we provide a structured suggestion for an assoc fn only for
+                    // expressions that are actually a fn call.
+                    let is_call = match field {
+                        Some(ast::ExprField { expr, .. }) => {
+                            matches!(expr.kind, ExprKind::Call(..))
+                        }
+                        _ => matches!(
+                            source,
+                            PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })),
+                        ),
+                    };
+
                     match &item.kind {
                         AssocItemKind::Fn(fn_)
-                        if !sig.decl.has_self() && fn_.sig.decl.has_self() => {
+                            if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() =>
+                        {
                             // Ensure that we only suggest `self.` if `self` is available,
                             // you can't call `fn foo(&self)` from `fn bar()` (#115992).
                             // We also want to mention that the method exists.
@@ -243,22 +272,27 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             ));
                             None
                         }
-                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => Some((
-                            sp,
-                            "consider using the method on `Self`",
-                            "self.".to_string(),
-                        )),
+                        AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => {
+                            span_label = Some((
+                                item.ident.span,
+                                "an associated function by that name is available on `Self` here",
+                            ));
+                            None
+                        }
+                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => {
+                            Some((sp, "consider using the method on `Self`", format!("{pre}self.")))
+                        }
                         AssocItemKind::Fn(_) => Some((
                             sp,
                             "consider using the associated function on `Self`",
-                            "Self::".to_string(),
+                            format!("{pre}Self::"),
                         )),
                         AssocItemKind::Const(..) => Some((
                             sp,
                             "consider using the associated constant on `Self`",
-                            "Self::".to_string(),
+                            format!("{pre}Self::"),
                         )),
-                        _ => None
+                        _ => None,
                     }
                 } else {
                     None
@@ -344,8 +378,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         prefix_path: &[Segment],
         following_seg: Option<&Segment>,
     ) -> Vec<ImportSuggestion> {
-        if let Some(segment) = prefix_path.last() &&
-            let Some(following_seg) = following_seg
+        if let Some(segment) = prefix_path.last()
+            && let Some(following_seg) = following_seg
         {
             let candidates = self.r.lookup_import_candidates(
                 segment.ident,
@@ -357,12 +391,16 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             candidates
                 .into_iter()
                 .filter(|candidate| {
-                    if let Some(def_id) = candidate.did &&
-                        let Some(module) = self.r.get_module(def_id) {
-                                Some(def_id) != self.parent_scope.module.opt_def_id() &&
-                                self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
-                                    key.ident.name == following_seg.ident.name
-                                })
+                    if let Some(def_id) = candidate.did
+                        && let Some(module) = self.r.get_module(def_id)
+                    {
+                        Some(def_id) != self.parent_scope.module.opt_def_id()
+                            && self
+                                .r
+                                .resolutions(module)
+                                .borrow()
+                                .iter()
+                                .any(|(key, _r)| key.ident.name == following_seg.ident.name)
                     } else {
                         false
                     }
@@ -621,17 +659,30 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
             {
                 let self_is_available = self.self_value_is_available(path[0].ident.span);
+                // Account for `Foo { field }` when suggesting `self.field` so we result on
+                // `Foo { field: self.field }`.
+                let pre = match source {
+                    PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))
+                        if expr
+                            .fields
+                            .iter()
+                            .any(|f| f.ident == path[0].ident && f.is_shorthand) =>
+                    {
+                        format!("{path_str}: ")
+                    }
+                    _ => String::new(),
+                };
                 match candidate {
-                    AssocSuggestion::Field => {
+                    AssocSuggestion::Field(field_span) => {
                         if self_is_available {
-                            err.span_suggestion(
-                                span,
+                            err.span_suggestion_verbose(
+                                span.shrink_to_lo(),
                                 "you might have meant to use the available field",
-                                format!("self.{path_str}"),
+                                format!("{pre}self."),
                                 Applicability::MachineApplicable,
                             );
                         } else {
-                            err.span_label(span, "a field by this name exists in `Self`");
+                            err.span_label(field_span, "a field by that name exists in `Self`");
                         }
                     }
                     AssocSuggestion::MethodWithSelf { called } if self_is_available => {
@@ -640,10 +691,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         } else {
                             "you might have meant to refer to the method"
                         };
-                        err.span_suggestion(
-                            span,
+                        err.span_suggestion_verbose(
+                            span.shrink_to_lo(),
                             msg,
-                            format!("self.{path_str}"),
+                            "self.".to_string(),
                             Applicability::MachineApplicable,
                         );
                     }
@@ -651,10 +702,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     | AssocSuggestion::AssocFn { .. }
                     | AssocSuggestion::AssocConst
                     | AssocSuggestion::AssocType => {
-                        err.span_suggestion(
-                            span,
+                        err.span_suggestion_verbose(
+                            span.shrink_to_lo(),
                             format!("you might have meant to {}", candidate.action()),
-                            format!("Self::{path_str}"),
+                            "Self::".to_string(),
                             Applicability::MachineApplicable,
                         );
                     }
@@ -699,11 +750,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         }
 
         // Try to find in last block rib
-        if let Some(rib) = &self.last_block_rib && let RibKind::Normal = rib.kind {
+        if let Some(rib) = &self.last_block_rib
+            && let RibKind::Normal = rib.kind
+        {
             for (ident, &res) in &rib.bindings {
-                if let Res::Local(_) = res && path.len() == 1 &&
-                    ident.span.eq_ctxt(path[0].ident.span) &&
-                    ident.name == path[0].ident.name {
+                if let Res::Local(_) = res
+                    && path.len() == 1
+                    && ident.span.eq_ctxt(path[0].ident.span)
+                    && ident.name == path[0].ident.name
+                {
                     err.span_help(
                         ident.span,
                         format!("the binding `{path_str}` is available in a different scope in the same function"),
@@ -819,9 +874,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         // (could be in a different file) or introduced in the same file as the typo
         // (could belong to a different crate)
         if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
-            && res
-                .opt_def_id()
-                .is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))
+            && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))
         {
             err.span_label(
                 sugg_span,
@@ -1026,12 +1079,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             && trait_ref.path.span == span
             && let PathSource::Trait(_) = source
             && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
-            && let Ok(self_ty_str) =
-                self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)
+            && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)
             && let Ok(trait_ref_str) =
                 self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)
         {
-                err.multipart_suggestion(
+            err.multipart_suggestion(
                     "`impl` items mention the trait being implemented first and the type it is being implemented for second",
                     vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
                     Applicability::MaybeIncorrect,
@@ -1058,12 +1110,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         source: PathSource<'_>,
         span: Span,
     ) -> bool {
-        if let PathSource::Expr(_) = source &&
-        let Some(Expr {
-                    span: expr_span,
-                    kind: ExprKind::Assign(lhs, _, _),
-                    ..
-                })  = self.diagnostic_metadata.in_if_condition {
+        if let PathSource::Expr(_) = source
+            && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) =
+                self.diagnostic_metadata.in_if_condition
+        {
             // Icky heuristic so we don't suggest:
             // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
             // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
@@ -1192,31 +1242,32 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         let mut has_self_arg = None;
         if let PathSource::Expr(Some(parent)) = source
             && let ExprKind::Call(_, args) = &parent.kind
-            && !args.is_empty() {
-                let mut expr_kind = &args[0].kind;
-                loop {
-                    match expr_kind {
-                        ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
-                            if arg_name.segments[0].ident.name == kw::SelfLower {
-                                let call_span = parent.span;
-                                let tail_args_span = if args.len() > 1 {
-                                    Some(Span::new(
-                                        args[1].span.lo(),
-                                        args.last().unwrap().span.hi(),
-                                        call_span.ctxt(),
-                                        None,
-                                    ))
-                                } else {
-                                    None
-                                };
-                                has_self_arg = Some((call_span, tail_args_span));
-                            }
-                            break;
+            && !args.is_empty()
+        {
+            let mut expr_kind = &args[0].kind;
+            loop {
+                match expr_kind {
+                    ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
+                        if arg_name.segments[0].ident.name == kw::SelfLower {
+                            let call_span = parent.span;
+                            let tail_args_span = if args.len() > 1 {
+                                Some(Span::new(
+                                    args[1].span.lo(),
+                                    args.last().unwrap().span.hi(),
+                                    call_span.ctxt(),
+                                    None,
+                                ))
+                            } else {
+                                None
+                            };
+                            has_self_arg = Some((call_span, tail_args_span));
                         }
-                        ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
-                        _ => break,
+                        break;
                     }
+                    ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
+                    _ => break,
                 }
+            }
         }
         has_self_arg
     }
@@ -1273,8 +1324,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 );
                 true
             } else if kind == DefKind::Struct
-            && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
-            && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
+                && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
+                && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
             {
                 // The LHS is a type that originates from a macro call.
                 // We have to add angle brackets around it.
@@ -1379,7 +1430,13 @@ 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 {
@@ -1667,11 +1724,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         resolution.full_res()
                     {
                         if let Some(field_ids) = self.r.field_def_ids(did) {
-                            if field_ids
+                            if let Some(field_id) = field_ids
                                 .iter()
-                                .any(|&field_id| ident.name == self.r.tcx.item_name(field_id))
+                                .find(|&&field_id| ident.name == self.r.tcx.item_name(field_id))
                             {
-                                return Some(AssocSuggestion::Field);
+                                return Some(AssocSuggestion::Field(self.r.def_span(*field_id)));
                             }
                         }
                     }
@@ -1765,7 +1822,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     }
                 }
 
-                if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) {
+                if let RibKind::MacroDefinition(def) = rib.kind
+                    && def == self.r.macro_def(ctxt)
+                {
                     // If an invocation of this macro created `ident`, give up on `ident`
                     // and switch to `ident`'s source from the macro definition.
                     ctxt.remove_mark();
@@ -1886,18 +1945,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
     // try to give a suggestion for this pattern: `name = blah`, which is common in other languages
     // suggest `let name = blah` to introduce a new binding
     fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
-        if let Some(Expr { kind: ExprKind::Assign(lhs, .. ), .. }) = self.diagnostic_metadata.in_assignment &&
-            let ast::ExprKind::Path(None, _) = lhs.kind {
-                if !ident_span.from_expansion() {
-                    err.span_suggestion_verbose(
-                        ident_span.shrink_to_lo(),
-                        "you might have meant to introduce a new binding",
-                        "let ".to_string(),
-                        Applicability::MaybeIncorrect,
-                    );
-                    return true;
-                }
+        if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) =
+            self.diagnostic_metadata.in_assignment
+            && let ast::ExprKind::Path(None, _) = lhs.kind
+        {
+            if !ident_span.from_expansion() {
+                err.span_suggestion_verbose(
+                    ident_span.shrink_to_lo(),
+                    "you might have meant to introduce a new binding",
+                    "let ".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+                return true;
             }
+        }
         false
     }
 
@@ -2358,7 +2419,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         continue;
                     }
 
-                    if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
+                    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,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 949c6ab5ac0..501747df5c9 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -7,6 +7,8 @@
 //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(extract_if)]
@@ -824,8 +826,10 @@ impl<'a> NameBindingData<'a> {
                 matches!(import.kind, ImportKind::ExternCrate { .. })
             }
             NameBindingKind::Module(module)
-                if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind
-                    => def_id.is_crate_root(),
+                if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind =>
+            {
+                def_id.is_crate_root()
+            }
             _ => false,
         }
     }
@@ -1074,8 +1078,8 @@ pub struct Resolver<'a, 'tcx> {
     /// Also includes of list of each fields visibility
     struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
 
-    /// Features enabled for this crate.
-    active_features: FxHashSet<Symbol>,
+    /// Features declared for this crate.
+    declared_features: FxHashSet<Symbol>,
 
     lint_buffer: LintBuffer,
 
@@ -1417,12 +1421,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             multi_segment_macro_resolutions: Default::default(),
             builtin_attrs: Default::default(),
             containers_deriving_copy: Default::default(),
-            active_features: features
-                .declared_lib_features
-                .iter()
-                .map(|(feat, ..)| *feat)
-                .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
-                .collect(),
+            declared_features: features.declared_features.clone(),
             lint_buffer: LintBuffer::default(),
             next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 90ae08ce37c..2ff6fb424e6 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -748,33 +748,45 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
                 path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
                     let mut suggestion = None;
-                    let (span, label, module) = if let PathResult::Failed { span, label, module, .. } = path_res {
-                        // try to suggest if it's not a macro, maybe a function
-                        if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
-                            && partial_res.unresolved_segments() == 0 {
-                            let sm = self.tcx.sess.source_map();
-                            let exclamation_span = sm.next_point(span);
-                            suggestion = Some((
-                                vec![(exclamation_span, "".to_string())],
-                                    format!("{} is not a macro, but a {}, try to remove `!`", Segment::names_to_string(&path), partial_res.base_res().descr()),
-                                    Applicability::MaybeIncorrect
+                    let (span, label, module) =
+                        if let PathResult::Failed { span, label, module, .. } = path_res {
+                            // try to suggest if it's not a macro, maybe a function
+                            if let PathResult::NonModule(partial_res) =
+                                self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+                                && partial_res.unresolved_segments() == 0
+                            {
+                                let sm = self.tcx.sess.source_map();
+                                let exclamation_span = sm.next_point(span);
+                                suggestion = Some((
+                                    vec![(exclamation_span, "".to_string())],
+                                    format!(
+                                        "{} is not a macro, but a {}, try to remove `!`",
+                                        Segment::names_to_string(&path),
+                                        partial_res.base_res().descr()
+                                    ),
+                                    Applicability::MaybeIncorrect,
                                 ));
-                        }
-                        (span, label, module)
-                    } else {
-                        (
-                            path_span,
-                            format!(
-                                "partially resolved path in {} {}",
-                                kind.article(),
-                                kind.descr()
-                            ),
-                            None,
-                        )
-                    };
+                            }
+                            (span, label, module)
+                        } else {
+                            (
+                                path_span,
+                                format!(
+                                    "partially resolved path in {} {}",
+                                    kind.article(),
+                                    kind.descr()
+                                ),
+                                None,
+                            )
+                        };
                     self.report_error(
                         span,
-                        ResolutionError::FailedToResolve { last_segment: path.last().map(|segment| segment.ident.name), label, suggestion, module },
+                        ResolutionError::FailedToResolve {
+                            last_segment: path.last().map(|segment| segment.ident.name),
+                            label,
+                            suggestion,
+                            module,
+                        },
                     );
                 }
                 PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
@@ -854,7 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let feature = stability.feature;
 
                 let is_allowed = |feature| {
-                    self.active_features.contains(&feature) || span.allows_unstable(feature)
+                    self.declared_features.contains(&feature) || span.allows_unstable(feature)
                 };
                 let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
                 if !is_allowed(feature) && !allowed_by_implication {
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 7c41c32d022..fe4b8c7f69c 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -346,7 +346,9 @@ pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool {
     for attr in attrs {
         if attr.has_name(sym::rustc_doc_primitive) {
             return true;
-        } else if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() {
+        } else if attr.has_name(sym::doc)
+            && let Some(items) = attr.meta_item_list()
+        {
             for item in items {
                 if item.has_name(sym::keyword) {
                     return true;