about summary refs log tree commit diff
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-08-19 11:36:53 +0000
committerbors <bors@rust-lang.org>2025-08-19 11:36:53 +0000
commit8c32e313cccf7df531e2d49ffb8227bb92304aee (patch)
tree7fd1e4b477f9942fd96d8cf68e63d3eea112777c /compiler/rustc_resolve
parent8365fcb2b840c95eeb0bc377af8bd498fad22245 (diff)
parent8baab4cdf77979aed3ed7a5617df651c3e933405 (diff)
downloadrust-8c32e313cccf7df531e2d49ffb8227bb92304aee.tar.gz
rust-8c32e313cccf7df531e2d49ffb8227bb92304aee.zip
Auto merge of #142487 - estebank:serde-attr-5, r=petrochenkov
Detect missing `derive` on unresolved attribute even when not imported

When encountering unresolved attributes, ensure the proc-macros for every crate in scope are added to the `macro_map` so that typos and missing `derive`s are properly detected.

```
error: cannot find attribute `sede` in this scope
  --> $DIR/missing-derive-3.rs:20:7
   |
LL |     #[sede(untagged)]
   |       ^^^^
   |
help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
   |
LL |     #[serde(untagged)]
   |         +

error: cannot find attribute `serde` in this scope
  --> $DIR/missing-derive-3.rs:14:7
   |
LL |     #[serde(untagged)]
   |       ^^^^^
   |
note: `serde` is imported here, but it is a crate, not an attribute
  --> $DIR/missing-derive-3.rs:4:1
   |
LL | extern crate serde;
   | ^^^^^^^^^^^^^^^^^^^
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
   |
LL + #[derive(Deserialize, Serialize)]
LL | enum B {
   |
```

Follow up to rust-lang/rust#134841. Fix rust-lang/rust#47608.
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs11
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs30
-rw-r--r--compiler/rustc_resolve/src/lib.rs4
3 files changed, 18 insertions, 27 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 1eb4e1199e6..2f1c9fe4c1d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -210,6 +210,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
+    /// Add every proc macro accessible from the current crate to the `macro_map` so diagnostics can
+    /// find them for suggestions.
+    pub(crate) fn register_macros_for_all_crates(&mut self) {
+        if !self.all_crate_macros_already_registered {
+            for def_id in self.cstore().all_proc_macro_def_ids() {
+                self.get_macro_by_def_id(def_id);
+            }
+            self.all_crate_macros_already_registered = true;
+        }
+    }
+
     pub(crate) fn build_reduced_graph(
         &mut self,
         fragment: &AstFragment,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index a437f86e377..ff39ba46d97 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1469,33 +1469,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         krate: &Crate,
         sugg_span: Option<Span>,
     ) {
-        // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
-        // for suggestions.
-        self.cm().visit_scopes(
-            ScopeSet::Macro(MacroKind::Derive),
-            &parent_scope,
-            ident.span.ctxt(),
-            |this, scope, _use_prelude, _ctxt| {
-                let Scope::Module(m, _) = scope else {
-                    return None;
-                };
-                for (_, resolution) in this.resolutions(m).borrow().iter() {
-                    let Some(binding) = resolution.borrow().best_binding() else {
-                        continue;
-                    };
-                    let Res::Def(DefKind::Macro(kinds), def_id) = binding.res() else {
-                        continue;
-                    };
-                    if !kinds.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) {
-                        continue;
-                    }
-                    // By doing this all *imported* macros get added to the `macro_map` even if they
-                    // are *unused*, which makes the later suggestions find them and work.
-                    let _ = this.get_macro_by_def_id(def_id);
-                }
-                None::<()>
-            },
-        );
+        // Bring all unused `derive` macros into `macro_map` so we ensure they can be used for
+        // suggestions.
+        self.register_macros_for_all_crates();
 
         let is_expected =
             &|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into()));
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index ca9c124fca6..c0a46e3b16b 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1267,6 +1267,10 @@ pub struct Resolver<'ra, 'tcx> {
 
     mods_with_parse_errors: FxHashSet<DefId>,
 
+    /// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we
+    /// don't need to run it more than once.
+    all_crate_macros_already_registered: bool = false,
+
     // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types
     // that were encountered during resolution. These names are used to generate item names
     // for APITs, so we don't want to leak details of resolution into these names.