Skip to content

Commit

Permalink
Look at proc-macro attributes when encountering unknown attribute
Browse files Browse the repository at this point in the history
```
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.
  • Loading branch information
estebank committed Dec 28, 2024
1 parent a7d68b9 commit 3c8c8a8
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 2 deletions.
28 changes: 28 additions & 0 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
false,
false,
None,
None,
) {
suggestions.extend(
ext.helper_attrs
Expand Down Expand Up @@ -1426,6 +1427,33 @@ 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.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().binding else {
continue;
};
let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
binding.res()
else {
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::<()>
},
);

let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
let suggestion = self.early_lookup_typo_candidate(
ScopeSet::Macro(macro_kind),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
true,
force,
ignore_import,
None,
) {
Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4367,7 +4367,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
if let Ok((_, res)) =
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None)
{
return Ok(Some(PartialRes::new(res)));
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
true,
force,
None,
None,
) {
Ok((Some(ext), _)) => {
if !ext.helper_attrs.is_empty() {
Expand Down Expand Up @@ -726,6 +727,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
trace: bool,
force: bool,
ignore_import: Option<Import<'ra>>,
suggestion_span: Option<Span>,
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
self.resolve_macro_or_delegation_path(
path,
Expand All @@ -736,7 +738,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None,
None,
ignore_import,
None,
suggestion_span,
)
}

Expand Down
12 changes: 12 additions & 0 deletions tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -583,18 +583,30 @@ error: cannot find attribute `multipart_suggestion` in this scope
|
LL | #[multipart_suggestion(no_crate_suggestion)]
| ^^^^^^^^^^^^^^^^^^^^
|
help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
|
LL | #[derive(Subdiagnostic)]
|

error: cannot find attribute `multipart_suggestion` in this scope
--> $DIR/diagnostic-derive.rs:647:3
|
LL | #[multipart_suggestion()]
| ^^^^^^^^^^^^^^^^^^^^
|
help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
|
LL | #[derive(Subdiagnostic)]
|

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

error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
--> $DIR/diagnostic-derive.rs:75:8
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/macros/auxiliary/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ force-host
//@ no-prefer-dynamic

#![crate_type = "proc-macro"]
#![feature(proc_macro_quote)]

extern crate proc_macro;

use proc_macro::*;

#[proc_macro_derive(Serialize, attributes(serde))]
pub fn serialize(ts: TokenStream) -> TokenStream {
quote!{}
}

#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn deserialize(ts: TokenStream) -> TokenStream {
quote!{}
}
33 changes: 33 additions & 0 deletions tests/ui/macros/missing-derive-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//@aux-build:serde.rs

// derive macros imported and used

extern crate serde;
use serde::{Serialize, Deserialize};

#[serde(untagged)] //~ ERROR cannot find attribute `serde`
enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
A,
B,
}

enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
A,
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
B,
}

enum C {
A,
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
B, //~^ HELP the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
}

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum D {
A,
B,
}

fn main() {}
47 changes: 47 additions & 0 deletions tests/ui/macros/missing-derive-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error: cannot find attribute `serde` in this scope
--> $DIR/missing-derive-1.rs:8:3
|
LL | #[serde(untagged)]
| ^^^^^
|
note: `serde` is imported here, but it is a crate, not an attribute
--> $DIR/missing-derive-1.rs:5:1
|
LL | extern crate serde;
| ^^^^^^^^^^^^^^^^^^^
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
|
LL + #[derive(Serialize, Deserialize)]
LL | enum A {
|

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

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

error: aborting due to 3 previous errors

26 changes: 26 additions & 0 deletions tests/ui/macros/missing-derive-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//@aux-build:serde.rs

// derive macros imported but unused

extern crate serde;
use serde::{Serialize, Deserialize};

#[serde(untagged)] //~ ERROR cannot find attribute `serde`
enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
A,
B,
}

enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`
A,
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
B,
}

enum C {
A,
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
B, //~^ HELP the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
}

fn main() {}
47 changes: 47 additions & 0 deletions tests/ui/macros/missing-derive-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error: cannot find attribute `sede` in this scope
--> $DIR/missing-derive-2.rs:22:7
|
LL | #[sede(untagged)]
| ^^^^
|
help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
|
LL | #[serde(untagged)]
| ~~~~~

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

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

error: aborting due to 3 previous errors

24 changes: 24 additions & 0 deletions tests/ui/macros/missing-derive-3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@aux-build:serde.rs

// derive macros not imported, but namespace imported. Not yet handled.
extern crate serde;

#[serde(untagged)] //~ ERROR cannot find attribute `serde`
enum A {
A,
B,
}

enum B {
A,
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
B,
}

enum C {
A,
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
B,
}

fn main() {}
32 changes: 32 additions & 0 deletions tests/ui/macros/missing-derive-3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
error: cannot find attribute `sede` in this scope
--> $DIR/missing-derive-3.rs:20:7
|
LL | #[sede(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;
| ^^^^^^^^^^^^^^^^^^^

error: cannot find attribute `serde` in this scope
--> $DIR/missing-derive-3.rs:6:3
|
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;
| ^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

0 comments on commit 3c8c8a8

Please sign in to comment.