Skip to content

Commit 409e0eb

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 rust-lang#47608.
1 parent 7f1d531 commit 409e0eb

File tree

12 files changed

+272
-2
lines changed

12 files changed

+272
-2
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+27
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,33 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14181418
krate: &Crate,
14191419
sugg_span: Option<Span>,
14201420
) {
1421+
// Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
1422+
// for suggestions.
1423+
self.visit_scopes(
1424+
ScopeSet::Macro(MacroKind::Derive),
1425+
&parent_scope,
1426+
ident.span.ctxt(),
1427+
|this, scope, _use_prelude, _ctxt| {
1428+
let Scope::Module(m, _) = scope else {
1429+
return None;
1430+
};
1431+
for (_, resolution) in this.resolutions(m).borrow().iter() {
1432+
let Some(binding) = resolution.borrow().binding else {
1433+
continue;
1434+
};
1435+
let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
1436+
binding.res()
1437+
else {
1438+
continue;
1439+
};
1440+
// By doing this all *imported* macros get added to the `macro_map` even if they
1441+
// are *unused*, which makes the later suggestions find them and work.
1442+
let _ = this.get_macro_by_def_id(def_id);
1443+
}
1444+
None::<()>
1445+
},
1446+
);
1447+
14211448
let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
14221449
let suggestion = self.early_lookup_typo_candidate(
14231450
ScopeSet::Macro(macro_kind),

compiler/rustc_resolve/src/ident.rs

+1
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
463463
true,
464464
force,
465465
ignore_import,
466+
None,
466467
) {
467468
Ok((Some(ext), _)) => {
468469
if ext.helper_attrs.contains(&ident.name) {

compiler/rustc_resolve/src/late.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4406,7 +4406,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
44064406
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
44074407
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
44084408
if let Ok((_, res)) =
4409-
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
4409+
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None)
44104410
{
44114411
return Ok(Some(PartialRes::new(res)));
44124412
}

compiler/rustc_resolve/src/macros.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
396396
true,
397397
force,
398398
None,
399+
None,
399400
) {
400401
Ok((Some(ext), _)) => {
401402
if !ext.helper_attrs.is_empty() {
@@ -693,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
693694
trace: bool,
694695
force: bool,
695696
ignore_import: Option<Import<'ra>>,
697+
suggestion_span: Option<Span>,
696698
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
697699
self.resolve_macro_or_delegation_path(
698700
path,
@@ -703,7 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
703705
None,
704706
None,
705707
ignore_import,
706-
None,
708+
suggestion_span,
707709
)
708710
}
709711

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

+12
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

+19
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

+33
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() {}
+47
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

+26
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() {}
+47
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

+24
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() {}
+32
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)