Auto merge of #134841 - estebank:serde-attr-4, r=wesleywiser

Look at proc-macro attributes when encountering unknown attribute

```
error: cannot find attribute `sede` in this scope
  --> $DIR/missing-derive-2.rs:22: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-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 {
   |
```

Partially address #47608. This PR doesn't find [macros that haven't yet been imported by name](af945cb86e).
This commit is contained in:
bors
2025-06-13 22:59:24 +00:00
16 changed files with 418 additions and 7 deletions

View File

@@ -7,7 +7,7 @@ use rustc_ast::{
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_attr_data_structures::{self as attr, Stability}; use rustc_attr_data_structures::{self as attr, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{ use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
@@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
false, false,
false, false,
None, None,
None,
) else { ) else {
continue; continue;
}; };
@@ -1482,7 +1483,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
parent_scope: &ParentScope<'ra>, parent_scope: &ParentScope<'ra>,
ident: Ident, ident: Ident,
krate: &Crate, 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 is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
let suggestion = self.early_lookup_typo_candidate( let suggestion = self.early_lookup_typo_candidate(
ScopeSet::Macro(macro_kind), ScopeSet::Macro(macro_kind),
@@ -1490,7 +1519,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ident, ident,
is_expected, 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 = let import_suggestions =
self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
@@ -1623,6 +1654,105 @@ 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<Span>,
) {
// 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: UnordMap<Symbol, Vec<_>> = UnordMap::default();
// We're collecting these in a hashmap, and handle ordering the output further down.
#[allow(rustc::potential_query_instability)]
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.
let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect();
derives.sort();
derives.dedup();
let msg = match &derives[..] {
[derive] => format!(" `{derive}`"),
[start @ .., last] => format!(
"s {} and `{last}`",
start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().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.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 = all_attrs.keys().map(|s| *s).into_sorted_stable_ord();
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 mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect();
macros.sort();
macros.dedup();
let msg = match &macros[..] {
[] => return,
[name] => format!(" `{name}` accepts"),
[start @ .., end] => format!(
"s {} and `{end}` accept",
start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().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( pub(crate) fn add_typo_suggestion(
&self, &self,
err: &mut Diag<'_>, err: &mut Diag<'_>,

View File

@@ -460,6 +460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
true, true,
force, force,
ignore_import, ignore_import,
None,
) { ) {
Ok((Some(ext), _)) => { Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) { if ext.helper_attrs.contains(&ident.name) {

View File

@@ -4509,7 +4509,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
if let Ok((_, res)) = 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))); return Ok(Some(PartialRes::new(res)));
} }

View File

@@ -1139,7 +1139,7 @@ pub struct Resolver<'ra, 'tcx> {
proc_macro_stubs: FxHashSet<LocalDefId>, proc_macro_stubs: FxHashSet<LocalDefId>,
/// Traces collected during macro resolution and validated when it's complete. /// Traces collected during macro resolution and validated when it's complete.
single_segment_macro_resolutions: single_segment_macro_resolutions:
Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>)>, Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>,
multi_segment_macro_resolutions: multi_segment_macro_resolutions:
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>,
builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>,

View File

@@ -12,7 +12,8 @@ use rustc_attr_data_structures::StabilityLevel;
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
use rustc_expand::base::{ use rustc_expand::base::{
DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
SyntaxExtensionKind,
}; };
use rustc_expand::compile_declarative_macro; use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{ use rustc_expand::expand::{
@@ -294,6 +295,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
&& self.tcx.def_kind(mod_def_id) == DefKind::Mod && self.tcx.def_kind(mod_def_id) == DefKind::Mod
}) })
.map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); .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( let (ext, res) = self.smart_resolve_macro_path(
path, path,
kind, kind,
@@ -304,6 +313,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
force, force,
deleg_impl, deleg_impl,
looks_like_invoc_in_mod_inert_attr, looks_like_invoc_in_mod_inert_attr,
sugg_span,
)?; )?;
let span = invoc.span(); let span = invoc.span();
@@ -386,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
true, true,
force, force,
None, None,
None,
) { ) {
Ok((Some(ext), _)) => { Ok((Some(ext), _)) => {
if !ext.helper_attrs.is_empty() { if !ext.helper_attrs.is_empty() {
@@ -528,6 +539,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
force: bool, force: bool,
deleg_impl: Option<LocalDefId>, deleg_impl: Option<LocalDefId>,
invoc_in_mod_inert_attr: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<LocalDefId>,
suggestion_span: Option<Span>,
) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> { ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_or_delegation_path( let (ext, res) = match self.resolve_macro_or_delegation_path(
path, path,
@@ -538,6 +550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
deleg_impl, deleg_impl,
invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)), invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
None, None,
suggestion_span,
) { ) {
Ok((Some(ext), res)) => (ext, res), Ok((Some(ext), res)) => (ext, res),
Ok((None, res)) => (self.dummy_ext(kind), res), Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -681,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
trace: bool, trace: bool,
force: bool, force: bool,
ignore_import: Option<Import<'ra>>, ignore_import: Option<Import<'ra>>,
suggestion_span: Option<Span>,
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
self.resolve_macro_or_delegation_path( self.resolve_macro_or_delegation_path(
path, path,
@@ -691,6 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None, None,
None, None,
ignore_import, ignore_import,
suggestion_span,
) )
} }
@@ -704,6 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
deleg_impl: Option<LocalDefId>, deleg_impl: Option<LocalDefId>,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
ignore_import: Option<Import<'ra>>, ignore_import: Option<Import<'ra>>,
suggestion_span: Option<Span>,
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
let path_span = ast_path.span; let path_span = ast_path.span;
let mut path = Segment::from_path(ast_path); let mut path = Segment::from_path(ast_path);
@@ -768,6 +784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
kind, kind,
*parent_scope, *parent_scope,
binding.ok(), binding.ok(),
suggestion_span,
)); ));
} }
@@ -905,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} }
let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); 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( match self.early_resolve_ident_in_lexical_scope(
ident, ident,
ScopeSet::Macro(kind), ScopeSet::Macro(kind),
@@ -946,7 +963,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
expected, expected,
ident, 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(); err.emit();
} }
} }

View File

@@ -583,18 +583,32 @@ error: cannot find attribute `multipart_suggestion` in this scope
| |
LL | #[multipart_suggestion(no_crate_suggestion)] 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 | struct MultipartSuggestion {
|
error: cannot find attribute `multipart_suggestion` in this scope error: cannot find attribute `multipart_suggestion` in this scope
--> $DIR/diagnostic-derive.rs:647:3 --> $DIR/diagnostic-derive.rs:647:3
| |
LL | #[multipart_suggestion()] 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 | struct MultipartSuggestion {
|
error: cannot find attribute `multipart_suggestion` in this scope error: cannot find attribute `multipart_suggestion` in this scope
--> $DIR/diagnostic-derive.rs:651:7 --> $DIR/diagnostic-derive.rs:651:7
| |
LL | #[multipart_suggestion(no_crate_suggestion)] 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` error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
--> $DIR/diagnostic-derive.rs:75:8 --> $DIR/diagnostic-derive.rs:75:8

View File

@@ -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!{}
}

View File

@@ -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 `Deserialize` and `Serialize`
A,
B,
}
enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`
A,
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
B,
}
enum C {
A,
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum D {
A,
B,
}
fn main() {}

View File

@@ -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 `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
LL + #[derive(Deserialize, Serialize)]
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 `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
LL + #[derive(Deserialize, Serialize)]
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 `Deserialize` and `Serialize` accept the similarly named `serde` attribute
|
LL | #[serde(untagged)]
| +
error: aborting due to 3 previous errors

View File

@@ -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 `Deserialize` and `Serialize`
A,
B,
}
enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`
A,
#[serde(untagged)] //~ ERROR cannot find attribute `serde`
B,
}
enum C {
A,
#[sede(untagged)] //~ ERROR cannot find attribute `sede`
B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
}
fn main() {}

View File

@@ -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 `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
|
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 `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
LL + #[derive(Deserialize, Serialize)]
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 `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
LL + #[derive(Deserialize, Serialize)]
LL | enum A {
|
error: aborting due to 3 previous errors

View File

@@ -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() {}

View File

@@ -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

View File

@@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope
| |
LL | #[empty_helper] 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 error: aborting due to 1 previous error

View File

@@ -16,6 +16,7 @@ error: cannot find attribute `empty_helper` in this scope
LL | #[derive(GenHelperUse)] 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) = 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 help: consider importing this attribute macro through its public re-export
| |
@@ -31,6 +32,7 @@ LL | #[empty_helper]
LL | gen_helper_use!(); LL | gen_helper_use!();
| ----------------- in this macro invocation | ----------------- 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) = 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 help: consider importing this attribute macro through its public re-export
| |

View File

@@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope
| |
LL | #[empty_helper] 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 error[E0603]: derive macro import `Empty` is private
--> $DIR/disappearing-resolution.rs:11:8 --> $DIR/disappearing-resolution.rs:11:8