Skip to content

Commit 3c8c8a8

Browse files
committed
Look at proc-macro attributes when encountering unknown attribute
``` error: cannot find attribute `sede` in this scope --> src/main.rs:18:7 | 18 | #[sede(untagged)] | ^^^^ | help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute | 18 | #[serde(untagged)] | ~~~~~ error: cannot find attribute `serde` in this scope --> src/main.rs:12:7 | 12 | #[serde(untagged)] | ^^^^^ | = note: `serde` is in scope, but it is a crate, not an attribute help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute | 10 | #[derive(Serialize, Deserialize)] | ``` Mitigate #47608.
1 parent a7d68b9 commit 3c8c8a8

File tree

12 files changed

+273
-2
lines changed

12 files changed

+273
-2
lines changed

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10541054
false,
10551055
false,
10561056
None,
1057+
None,
10571058
) {
10581059
suggestions.extend(
10591060
ext.helper_attrs
@@ -1426,6 +1427,33 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14261427
krate: &Crate,
14271428
sugg_span: Option<Span>,
14281429
) {
1430+
// Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
1431+
// for suggestions.
1432+
self.visit_scopes(
1433+
ScopeSet::Macro(MacroKind::Derive),
1434+
&parent_scope,
1435+
ident.span.ctxt(),
1436+
|this, scope, _use_prelude, _ctxt| {
1437+
let Scope::Module(m, _) = scope else {
1438+
return None;
1439+
};
1440+
for (_, resolution) in this.resolutions(m).borrow().iter() {
1441+
let Some(binding) = resolution.borrow().binding else {
1442+
continue;
1443+
};
1444+
let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
1445+
binding.res()
1446+
else {
1447+
continue;
1448+
};
1449+
// By doing this all *imported* macros get added to the `macro_map` even if they
1450+
// are *unused*, which makes the later suggestions find them and work.
1451+
let _ = this.get_macro_by_def_id(def_id);
1452+
}
1453+
None::<()>
1454+
},
1455+
);
1456+
14291457
let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
14301458
let suggestion = self.early_lookup_typo_candidate(
14311459
ScopeSet::Macro(macro_kind),

compiler/rustc_resolve/src/ident.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
465465
true,
466466
force,
467467
ignore_import,
468+
None,
468469
) {
469470
Ok((Some(ext), _)) => {
470471
if ext.helper_attrs.contains(&ident.name) {

compiler/rustc_resolve/src/late.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4367,7 +4367,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
43674367
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
43684368
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
43694369
if let Ok((_, res)) =
4370-
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
4370+
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None)
43714371
{
43724372
return Ok(Some(PartialRes::new(res)));
43734373
}

compiler/rustc_resolve/src/macros.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
418418
true,
419419
force,
420420
None,
421+
None,
421422
) {
422423
Ok((Some(ext), _)) => {
423424
if !ext.helper_attrs.is_empty() {
@@ -726,6 +727,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
726727
trace: bool,
727728
force: bool,
728729
ignore_import: Option<Import<'ra>>,
730+
suggestion_span: Option<Span>,
729731
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
730732
self.resolve_macro_or_delegation_path(
731733
path,
@@ -736,7 +738,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
736738
None,
737739
None,
738740
ignore_import,
739-
None,
741+
suggestion_span,
740742
)
741743
}
742744

tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,30 @@ error: cannot find attribute `multipart_suggestion` in this scope
583583
|
584584
LL | #[multipart_suggestion(no_crate_suggestion)]
585585
| ^^^^^^^^^^^^^^^^^^^^
586+
|
587+
help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
588+
|
589+
LL | #[derive(Subdiagnostic)]
590+
|
586591

587592
error: cannot find attribute `multipart_suggestion` in this scope
588593
--> $DIR/diagnostic-derive.rs:647:3
589594
|
590595
LL | #[multipart_suggestion()]
591596
| ^^^^^^^^^^^^^^^^^^^^
597+
|
598+
help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
599+
|
600+
LL | #[derive(Subdiagnostic)]
601+
|
592602

593603
error: cannot find attribute `multipart_suggestion` in this scope
594604
--> $DIR/diagnostic-derive.rs:651:7
595605
|
596606
LL | #[multipart_suggestion(no_crate_suggestion)]
597607
| ^^^^^^^^^^^^^^^^^^^^
608+
|
609+
= note: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
598610

599611
error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
600612
--> $DIR/diagnostic-derive.rs:75:8

tests/ui/macros/auxiliary/serde.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ force-host
2+
//@ no-prefer-dynamic
3+
4+
#![crate_type = "proc-macro"]
5+
#![feature(proc_macro_quote)]
6+
7+
extern crate proc_macro;
8+
9+
use proc_macro::*;
10+
11+
#[proc_macro_derive(Serialize, attributes(serde))]
12+
pub fn serialize(ts: TokenStream) -> TokenStream {
13+
quote!{}
14+
}
15+
16+
#[proc_macro_derive(Deserialize, attributes(serde))]
17+
pub fn deserialize(ts: TokenStream) -> TokenStream {
18+
quote!{}
19+
}

tests/ui/macros/missing-derive-1.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@aux-build:serde.rs
2+
3+
// derive macros imported and used
4+
5+
extern crate serde;
6+
use serde::{Serialize, Deserialize};
7+
8+
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
9+
enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
10+
A,
11+
B,
12+
}
13+
14+
enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
15+
A,
16+
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
17+
B,
18+
}
19+
20+
enum C {
21+
A,
22+
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
23+
B, //~^ HELP the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
24+
}
25+
26+
#[derive(Serialize, Deserialize)]
27+
#[serde(untagged)]
28+
enum D {
29+
A,
30+
B,
31+
}
32+
33+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: cannot find attribute `serde` in this scope
2+
--> $DIR/missing-derive-1.rs:8:3
3+
|
4+
LL | #[serde(untagged)]
5+
| ^^^^^
6+
|
7+
note: `serde` is imported here, but it is a crate, not an attribute
8+
--> $DIR/missing-derive-1.rs:5:1
9+
|
10+
LL | extern crate serde;
11+
| ^^^^^^^^^^^^^^^^^^^
12+
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
13+
|
14+
LL + #[derive(Serialize, Deserialize)]
15+
LL | enum A {
16+
|
17+
18+
error: cannot find attribute `serde` in this scope
19+
--> $DIR/missing-derive-1.rs:16:7
20+
|
21+
LL | #[serde(untagged)]
22+
| ^^^^^
23+
|
24+
note: `serde` is imported here, but it is a crate, not an attribute
25+
--> $DIR/missing-derive-1.rs:5:1
26+
|
27+
LL | extern crate serde;
28+
| ^^^^^^^^^^^^^^^^^^^
29+
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
30+
|
31+
LL + #[derive(Serialize, Deserialize)]
32+
LL | enum B {
33+
|
34+
35+
error: cannot find attribute `sede` in this scope
36+
--> $DIR/missing-derive-1.rs:22:7
37+
|
38+
LL | #[sede(untagged)]
39+
| ^^^^
40+
|
41+
help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
42+
|
43+
LL | #[serde(untagged)]
44+
| ~~~~~
45+
46+
error: aborting due to 3 previous errors
47+

tests/ui/macros/missing-derive-2.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@aux-build:serde.rs
2+
3+
// derive macros imported but unused
4+
5+
extern crate serde;
6+
use serde::{Serialize, Deserialize};
7+
8+
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
9+
enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
10+
A,
11+
B,
12+
}
13+
14+
enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
15+
A,
16+
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
17+
B,
18+
}
19+
20+
enum C {
21+
A,
22+
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
23+
B, //~^ HELP the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
24+
}
25+
26+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: cannot find attribute `sede` in this scope
2+
--> $DIR/missing-derive-2.rs:22:7
3+
|
4+
LL | #[sede(untagged)]
5+
| ^^^^
6+
|
7+
help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
8+
|
9+
LL | #[serde(untagged)]
10+
| ~~~~~
11+
12+
error: cannot find attribute `serde` in this scope
13+
--> $DIR/missing-derive-2.rs:16:7
14+
|
15+
LL | #[serde(untagged)]
16+
| ^^^^^
17+
|
18+
note: `serde` is imported here, but it is a crate, not an attribute
19+
--> $DIR/missing-derive-2.rs:5:1
20+
|
21+
LL | extern crate serde;
22+
| ^^^^^^^^^^^^^^^^^^^
23+
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
24+
|
25+
LL + #[derive(Serialize, Deserialize)]
26+
LL | enum B {
27+
|
28+
29+
error: cannot find attribute `serde` in this scope
30+
--> $DIR/missing-derive-2.rs:8:3
31+
|
32+
LL | #[serde(untagged)]
33+
| ^^^^^
34+
|
35+
note: `serde` is imported here, but it is a crate, not an attribute
36+
--> $DIR/missing-derive-2.rs:5:1
37+
|
38+
LL | extern crate serde;
39+
| ^^^^^^^^^^^^^^^^^^^
40+
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
41+
|
42+
LL + #[derive(Serialize, Deserialize)]
43+
LL | enum A {
44+
|
45+
46+
error: aborting due to 3 previous errors
47+

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@aux-build:serde.rs
2+
3+
// derive macros not imported, but namespace imported. Not yet handled.
4+
extern crate serde;
5+
6+
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
7+
enum A {
8+
A,
9+
B,
10+
}
11+
12+
enum B {
13+
A,
14+
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
15+
B,
16+
}
17+
18+
enum C {
19+
A,
20+
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
21+
B,
22+
}
23+
24+
fn main() {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: cannot find attribute `sede` in this scope
2+
--> $DIR/missing-derive-3.rs:20:7
3+
|
4+
LL | #[sede(untagged)]
5+
| ^^^^
6+
7+
error: cannot find attribute `serde` in this scope
8+
--> $DIR/missing-derive-3.rs:14:7
9+
|
10+
LL | #[serde(untagged)]
11+
| ^^^^^
12+
|
13+
note: `serde` is imported here, but it is a crate, not an attribute
14+
--> $DIR/missing-derive-3.rs:4:1
15+
|
16+
LL | extern crate serde;
17+
| ^^^^^^^^^^^^^^^^^^^
18+
19+
error: cannot find attribute `serde` in this scope
20+
--> $DIR/missing-derive-3.rs:6:3
21+
|
22+
LL | #[serde(untagged)]
23+
| ^^^^^
24+
|
25+
note: `serde` is imported here, but it is a crate, not an attribute
26+
--> $DIR/missing-derive-3.rs:4:1
27+
|
28+
LL | extern crate serde;
29+
| ^^^^^^^^^^^^^^^^^^^
30+
31+
error: aborting due to 3 previous errors
32+

0 commit comments

Comments
 (0)