Skip to content

Commit d1699eb

Browse files
committed
Detect missing derive on unresolved attribute even when not imported
``` 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 { | ```
1 parent 64c81fd commit d1699eb

File tree

6 files changed

+50
-26
lines changed

6 files changed

+50
-26
lines changed

compiler/rustc_metadata/src/creader.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateS
3232
use rustc_session::lint::{self, BuiltinLintDiag};
3333
use rustc_session::output::validate_crate_name;
3434
use rustc_session::search_paths::PathKind;
35+
use rustc_span::def_id::DefId;
3536
use rustc_span::edition::Edition;
3637
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
3738
use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
@@ -276,6 +277,12 @@ impl CStore {
276277
.filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
277278
}
278279

280+
pub fn all_proc_macro_def_ids(&self) -> Vec<DefId> {
281+
self.iter_crate_data()
282+
.flat_map(|(krate, data)| data.proc_macros_for_crate(krate, self))
283+
.collect()
284+
}
285+
279286
fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> {
280287
self.metas
281288
.iter_enumerated_mut()

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,16 @@ impl CrateMetadata {
19491949
self.root.is_proc_macro_crate()
19501950
}
19511951

1952+
pub(crate) fn proc_macros_for_crate(&self, krate: CrateNum, cstore: &CStore) -> Vec<DefId> {
1953+
let Some(data) = self.root.proc_macro_data.as_ref() else {
1954+
return vec![];
1955+
};
1956+
data.macros
1957+
.decode(CrateMetadataRef { cdata: self, cstore })
1958+
.map(|index| DefId { index, krate })
1959+
.collect()
1960+
}
1961+
19521962
pub(crate) fn name(&self) -> Symbol {
19531963
self.root.header.name
19541964
}

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
169169
}
170170
}
171171

172+
/// Add every proc macro accessible from the current crate to the `macro_map` so diagnostics can
173+
/// find them for suggestions.
174+
pub(crate) fn register_macros_for_all_crates(&mut self) {
175+
let def_ids = self.cstore().all_proc_macro_def_ids();
176+
for def_id in def_ids {
177+
self.get_macro_by_def_id(def_id);
178+
}
179+
}
180+
172181
pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> &MacroData {
173182
if self.macro_map.contains_key(&def_id) {
174183
return &self.macro_map[&def_id];

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,32 +1485,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14851485
krate: &Crate,
14861486
sugg_span: Option<Span>,
14871487
) {
1488-
// Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
1489-
// for suggestions.
1490-
self.visit_scopes(
1491-
ScopeSet::Macro(MacroKind::Derive),
1492-
&parent_scope,
1493-
ident.span.ctxt(),
1494-
|this, scope, _use_prelude, _ctxt| {
1495-
let Scope::Module(m, _) = scope else {
1496-
return None;
1497-
};
1498-
for (_, resolution) in this.resolutions(m).borrow().iter() {
1499-
let Some(binding) = resolution.borrow().binding else {
1500-
continue;
1501-
};
1502-
let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
1503-
binding.res()
1504-
else {
1505-
continue;
1506-
};
1507-
// By doing this all *imported* macros get added to the `macro_map` even if they
1508-
// are *unused*, which makes the later suggestions find them and work.
1509-
let _ = this.get_macro_by_def_id(def_id);
1510-
}
1511-
None::<()>
1512-
},
1513-
);
1488+
// Bring all unused `derive` macros into `macro_map` so we ensure they can be used for
1489+
// suggestions.
1490+
self.register_macros_for_all_crates();
15141491

15151492
let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
15161493
let suggestion = self.early_lookup_typo_candidate(

tests/ui/macros/missing-derive-3.stderr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error: cannot find attribute `sede` in this scope
33
|
44
LL | #[sede(untagged)]
55
| ^^^^
6+
|
7+
help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
8+
|
9+
LL | #[serde(untagged)]
10+
| +
611

712
error: cannot find attribute `serde` in this scope
813
--> $DIR/missing-derive-3.rs:14:7
@@ -15,6 +20,11 @@ note: `serde` is imported here, but it is a crate, not an attribute
1520
|
1621
LL | extern crate serde;
1722
| ^^^^^^^^^^^^^^^^^^^
23+
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
24+
|
25+
LL + #[derive(Deserialize, Serialize)]
26+
LL | enum B {
27+
|
1828

1929
error: cannot find attribute `serde` in this scope
2030
--> $DIR/missing-derive-3.rs:6:3
@@ -27,6 +37,11 @@ note: `serde` is imported here, but it is a crate, not an attribute
2737
|
2838
LL | extern crate serde;
2939
| ^^^^^^^^^^^^^^^^^^^
40+
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
41+
|
42+
LL + #[derive(Deserialize, Serialize)]
43+
LL | enum A {
44+
|
3045

3146
error: aborting due to 3 previous errors
3247

tests/ui/proc-macro/derive-helper-legacy-spurious.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ error: cannot find attribute `empty_helper` in this scope
99
|
1010
LL | #[empty_helper]
1111
| ^^^^^^^^^^^^
12+
|
13+
help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
14+
|
15+
LL + #[derive(Empty)]
16+
LL | struct Foo {}
17+
|
1218

1319
error: aborting due to 2 previous errors
1420

0 commit comments

Comments
 (0)