From 7f1d531608846f67d8b81d22294583ea7d1a7991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 28 Dec 2024 02:19:35 +0000 Subject: [PATCH 1/4] Detect when attribute is provided by missing `derive` macro ``` error: cannot find attribute `empty_helper` in this scope --> $DIR/derive-helper-legacy-limits.rs:17:3 | LL | #[empty_helper] | ^^^^^^^^^^^^ | help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute | LL + #[derive(Empty)] LL | struct S2; | ``` --- compiler/rustc_resolve/src/diagnostics.rs | 107 +++++++++++++++++- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 28 ++++- .../derive-helper-legacy-limits.stderr | 6 + .../proc-macro/derive-helper-shadowing.stderr | 2 + .../proc-macro/disappearing-resolution.stderr | 6 + 6 files changed, 145 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3405c89b79ab..74b8d7d96c723 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,7 +5,7 @@ use rustc_ast::{ self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, }; use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -1416,6 +1416,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ident: Ident, krate: &Crate, + sugg_span: Option, ) { let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( @@ -1424,7 +1425,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, is_expected, ); - self.add_typo_suggestion(err, suggestion, ident.span); + if !self.add_typo_suggestion(err, suggestion, ident.span) { + self.detect_derive_attribute(err, ident, parent_scope, sugg_span); + } let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); @@ -1557,6 +1560,106 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Given an attribute macro that failed to be resolved, look for `derive` macros that could + /// provide it, either as-is or with small typos. + fn detect_derive_attribute( + &self, + err: &mut Diag<'_>, + ident: Ident, + parent_scope: &ParentScope<'ra>, + sugg_span: Option, + ) { + // Find all of the `derive`s in scope and collect their corresponding declared + // attributes. + // FIXME: this only works if the crate that owns the macro that has the helper_attr + // has already been imported. + let mut derives = vec![]; + let mut all_attrs: FxHashMap> = FxHashMap::default(); + for (def_id, data) in &self.macro_map { + for helper_attr in &data.ext.helper_attrs { + let item_name = self.tcx.item_name(*def_id); + all_attrs.entry(*helper_attr).or_default().push(item_name); + if helper_attr == &ident.name { + derives.push(item_name); + } + } + } + let kind = MacroKind::Derive.descr(); + if !derives.is_empty() { + // We found an exact match for the missing attribute in a `derive` macro. Suggest it. + derives.sort(); + derives.dedup(); + let msg = match &derives[..] { + [derive] => format!(" `{derive}`"), + [start @ .., last] => format!( + "s {} and `{last}`", + start.iter().map(|d| format!("`{d}`")).collect::>().join(", ") + ), + [] => unreachable!("we checked for this to be non-empty 10 lines above!?"), + }; + let msg = format!( + "`{}` is an attribute that can be used by the {kind}{msg}, you might be \ + missing a `derive` attribute", + ident.name, + ); + let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind + { + let span = self.def_span(id); + if span.from_expansion() { + None + } else { + // For enum variants sugg_span is empty but we can get the enum's Span. + Some(span.shrink_to_lo()) + } + } else { + // For items this `Span` will be populated, everything else it'll be None. + sugg_span + }; + match sugg_span { + Some(span) => { + err.span_suggestion_verbose( + span, + msg, + format!( + "#[derive({})]\n", + derives + .iter() + .map(|d| d.to_string()) + .collect::>() + .join(", ") + ), + Applicability::MaybeIncorrect, + ); + } + None => { + err.note(msg); + } + } + } else { + // We didn't find an exact match. Look for close matches. If any, suggest fixing typo. + let all_attr_names: Vec = all_attrs.keys().cloned().collect(); + if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None) + && let Some(macros) = all_attrs.get(&best_match) + { + let msg = match ¯os[..] { + [] => return, + [name] => format!(" `{name}` accepts"), + [start @ .., end] => format!( + "s {} and `{end}` accept", + start.iter().map(|m| format!("`{m}`")).collect::>().join(", "), + ), + }; + let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute"); + err.span_suggestion_verbose( + ident.span, + msg, + best_match, + Applicability::MaybeIncorrect, + ); + } + } + } + pub(crate) fn add_typo_suggestion( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f724ecf76b3cc..8357d5e48d98b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1146,7 +1146,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option>)>, + Vec<(Ident, MacroKind, ParentScope<'ra>, Option>, Option)>, multi_segment_macro_resolutions: Vec<(Vec, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 984dfff3ea56e..533a7eeaaadb8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -12,7 +12,8 @@ use rustc_attr_parsing::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, StashKey}; use rustc_expand::base::{ - DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, + Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, + SyntaxExtensionKind, }; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ @@ -287,6 +288,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { && self.tcx.def_kind(mod_def_id) == DefKind::Mod }) .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); + let sugg_span = match &invoc.kind { + InvocationKind::Attr { item: Annotatable::Item(item), .. } + if !item.span.from_expansion() => + { + Some(item.span.shrink_to_lo()) + } + _ => None, + }; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -297,6 +306,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { force, deleg_impl, looks_like_invoc_in_mod_inert_attr, + sugg_span, )?; let span = invoc.span(); @@ -528,6 +538,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, deleg_impl: Option, invoc_in_mod_inert_attr: Option, + suggestion_span: Option, ) -> Result<(Arc, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_or_delegation_path( path, @@ -538,6 +549,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl, invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)), None, + suggestion_span, ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), @@ -691,6 +703,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, None, ignore_import, + None, ) } @@ -704,6 +717,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl: Option, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, ignore_import: Option>, + suggestion_span: Option, ) -> Result<(Option>, Res), Determinacy> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); @@ -768,6 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind, *parent_scope, binding.ok(), + suggestion_span, )); } @@ -905,7 +920,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); - for (ident, kind, parent_scope, initial_binding) in macro_resolutions { + for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { match self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), @@ -946,7 +961,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); + self.unresolved_macro_suggestions( + &mut err, + kind, + &parent_scope, + ident, + krate, + sugg_span, + ); err.emit(); } } diff --git a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr index f5cd455435d4a..df3c5c47ddb2d 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr +++ b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr @@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S2; + | error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index f284b1c54dd61..1206778bb2352 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -16,6 +16,7 @@ error: cannot find attribute `empty_helper` in this scope LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | @@ -31,6 +32,7 @@ LL | #[empty_helper] LL | gen_helper_use!(); | ----------------- in this macro invocation | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | diff --git a/tests/ui/proc-macro/disappearing-resolution.stderr b/tests/ui/proc-macro/disappearing-resolution.stderr index 734e0cd2ab6df..6c0f1a52915f6 100644 --- a/tests/ui/proc-macro/disappearing-resolution.stderr +++ b/tests/ui/proc-macro/disappearing-resolution.stderr @@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S; + | error[E0603]: derive macro import `Empty` is private --> $DIR/disappearing-resolution.rs:11:8 From 409e0eb16214fee1aad8c50bca1b4e4f167b5c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Mar 2023 19:16:19 +0000 Subject: [PATCH 2/4] 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. --- compiler/rustc_resolve/src/diagnostics.rs | 27 +++++++++++ compiler/rustc_resolve/src/ident.rs | 1 + compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 4 +- .../diagnostic-derive.stderr | 12 +++++ tests/ui/macros/auxiliary/serde.rs | 19 ++++++++ tests/ui/macros/missing-derive-1.rs | 33 +++++++++++++ tests/ui/macros/missing-derive-1.stderr | 47 +++++++++++++++++++ tests/ui/macros/missing-derive-2.rs | 26 ++++++++++ tests/ui/macros/missing-derive-2.stderr | 47 +++++++++++++++++++ tests/ui/macros/missing-derive-3.rs | 24 ++++++++++ tests/ui/macros/missing-derive-3.stderr | 32 +++++++++++++ 12 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 tests/ui/macros/auxiliary/serde.rs create mode 100644 tests/ui/macros/missing-derive-1.rs create mode 100644 tests/ui/macros/missing-derive-1.stderr create mode 100644 tests/ui/macros/missing-derive-2.rs create mode 100644 tests/ui/macros/missing-derive-2.stderr create mode 100644 tests/ui/macros/missing-derive-3.rs create mode 100644 tests/ui/macros/missing-derive-3.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 74b8d7d96c723..2e0a0abe8bcc2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1418,6 +1418,33 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { krate: &Crate, sugg_span: Option, ) { + // 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), diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index d9776be4dd0a6..bb55f6736ae6e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -463,6 +463,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, force, ignore_import, + None, ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 79479986d075f..b7779705185ef 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4406,7 +4406,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))); } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 533a7eeaaadb8..9f05a86474817 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -396,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { true, force, None, + None, ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { @@ -693,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trace: bool, force: bool, ignore_import: Option>, + suggestion_span: Option, ) -> Result<(Option>, Res), Determinacy> { self.resolve_macro_or_delegation_path( path, @@ -703,7 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, None, ignore_import, - None, + suggestion_span, ) } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 03fca17aa55d4..0b0defe1e027d 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -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 diff --git a/tests/ui/macros/auxiliary/serde.rs b/tests/ui/macros/auxiliary/serde.rs new file mode 100644 index 0000000000000..355b650bcf390 --- /dev/null +++ b/tests/ui/macros/auxiliary/serde.rs @@ -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!{} +} diff --git a/tests/ui/macros/missing-derive-1.rs b/tests/ui/macros/missing-derive-1.rs new file mode 100644 index 0000000000000..db6f7b70f3f57 --- /dev/null +++ b/tests/ui/macros/missing-derive-1.rs @@ -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() {} diff --git a/tests/ui/macros/missing-derive-1.stderr b/tests/ui/macros/missing-derive-1.stderr new file mode 100644 index 0000000000000..d9dd23f049158 --- /dev/null +++ b/tests/ui/macros/missing-derive-1.stderr @@ -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 + diff --git a/tests/ui/macros/missing-derive-2.rs b/tests/ui/macros/missing-derive-2.rs new file mode 100644 index 0000000000000..a51c5e4073d02 --- /dev/null +++ b/tests/ui/macros/missing-derive-2.rs @@ -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() {} diff --git a/tests/ui/macros/missing-derive-2.stderr b/tests/ui/macros/missing-derive-2.stderr new file mode 100644 index 0000000000000..1af01afb90fdb --- /dev/null +++ b/tests/ui/macros/missing-derive-2.stderr @@ -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 + diff --git a/tests/ui/macros/missing-derive-3.rs b/tests/ui/macros/missing-derive-3.rs new file mode 100644 index 0000000000000..8add81988901a --- /dev/null +++ b/tests/ui/macros/missing-derive-3.rs @@ -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() {} diff --git a/tests/ui/macros/missing-derive-3.stderr b/tests/ui/macros/missing-derive-3.stderr new file mode 100644 index 0000000000000..0a7ed8d08763c --- /dev/null +++ b/tests/ui/macros/missing-derive-3.stderr @@ -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 + From e7fc315698b86c5699205b56d730b49ebcf3ad06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 28 Dec 2024 04:38:44 +0000 Subject: [PATCH 3/4] fix test --- .../ui-fulldeps/session-diagnostic/diagnostic-derive.stderr | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 0b0defe1e027d..001699b2bc726 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -586,7 +586,8 @@ 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)] +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { | error: cannot find attribute `multipart_suggestion` in this scope @@ -597,7 +598,8 @@ 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)] +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { | error: cannot find attribute `multipart_suggestion` in this scope From b2f9a3f4b6b4a15780d9babd0ef35770db1cab43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Jan 2025 22:30:45 +0000 Subject: [PATCH 4/4] fix rebase --- compiler/rustc_resolve/src/diagnostics.rs | 1 + tests/ui/macros/missing-derive-1.rs | 2 +- tests/ui/macros/missing-derive-1.stderr | 4 ++-- tests/ui/macros/missing-derive-2.rs | 2 +- tests/ui/macros/missing-derive-2.stderr | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2e0a0abe8bcc2..3d281583a0177 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1041,6 +1041,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, false, None, + None, ) else { continue; }; diff --git a/tests/ui/macros/missing-derive-1.rs b/tests/ui/macros/missing-derive-1.rs index db6f7b70f3f57..b5221fbca60a8 100644 --- a/tests/ui/macros/missing-derive-1.rs +++ b/tests/ui/macros/missing-derive-1.rs @@ -20,7 +20,7 @@ enum B { //~ HELP `serde` is an attribute that can be used by the derive macros enum C { A, #[sede(untagged)] //~ ERROR cannot find attribute `sede` - B, //~^ HELP the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute } #[derive(Serialize, Deserialize)] diff --git a/tests/ui/macros/missing-derive-1.stderr b/tests/ui/macros/missing-derive-1.stderr index d9dd23f049158..d7255d5937e06 100644 --- a/tests/ui/macros/missing-derive-1.stderr +++ b/tests/ui/macros/missing-derive-1.stderr @@ -38,10 +38,10 @@ error: cannot find attribute `sede` in this scope LL | #[sede(untagged)] | ^^^^ | -help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute | LL | #[serde(untagged)] - | ~~~~~ + | + error: aborting due to 3 previous errors diff --git a/tests/ui/macros/missing-derive-2.rs b/tests/ui/macros/missing-derive-2.rs index a51c5e4073d02..754aab0287ade 100644 --- a/tests/ui/macros/missing-derive-2.rs +++ b/tests/ui/macros/missing-derive-2.rs @@ -20,7 +20,7 @@ enum B { //~ HELP `serde` is an attribute that can be used by the derive macros enum C { A, #[sede(untagged)] //~ ERROR cannot find attribute `sede` - B, //~^ HELP the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute } fn main() {} diff --git a/tests/ui/macros/missing-derive-2.stderr b/tests/ui/macros/missing-derive-2.stderr index 1af01afb90fdb..7234515bde2cc 100644 --- a/tests/ui/macros/missing-derive-2.stderr +++ b/tests/ui/macros/missing-derive-2.stderr @@ -4,10 +4,10 @@ error: cannot find attribute `sede` in this scope LL | #[sede(untagged)] | ^^^^ | -help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute +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-2.rs:16:7