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:
@@ -7,7 +7,7 @@ use rustc_ast::{
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_data_structures::{self as attr, Stability};
|
||||
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::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
|
||||
@@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
@@ -1482,7 +1483,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
parent_scope: &ParentScope<'ra>,
|
||||
ident: Ident,
|
||||
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),
|
||||
@@ -1490,7 +1519,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);
|
||||
@@ -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 ¯os[..] {
|
||||
[] => 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(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
|
||||
@@ -460,6 +460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
true,
|
||||
force,
|
||||
ignore_import,
|
||||
None,
|
||||
) {
|
||||
Ok((Some(ext), _)) => {
|
||||
if ext.helper_attrs.contains(&ident.name) {
|
||||
|
||||
@@ -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 = 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)));
|
||||
}
|
||||
|
||||
@@ -1139,7 +1139,7 @@ pub struct Resolver<'ra, 'tcx> {
|
||||
proc_macro_stubs: FxHashSet<LocalDefId>,
|
||||
/// Traces collected during macro resolution and validated when it's complete.
|
||||
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:
|
||||
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>,
|
||||
builtin_attrs: Vec<(Ident, ParentScope<'ra>)>,
|
||||
|
||||
@@ -12,7 +12,8 @@ use rustc_attr_data_structures::StabilityLevel;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{Applicability, DiagCtxtHandle, 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::{
|
||||
@@ -294,6 +295,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,
|
||||
@@ -304,6 +313,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();
|
||||
@@ -386,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
|
||||
true,
|
||||
force,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
Ok((Some(ext), _)) => {
|
||||
if !ext.helper_attrs.is_empty() {
|
||||
@@ -528,6 +539,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
force: bool,
|
||||
deleg_impl: Option<LocalDefId>,
|
||||
invoc_in_mod_inert_attr: Option<LocalDefId>,
|
||||
suggestion_span: Option<Span>,
|
||||
) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> {
|
||||
let (ext, res) = match self.resolve_macro_or_delegation_path(
|
||||
path,
|
||||
@@ -538,6 +550,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),
|
||||
@@ -681,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
trace: bool,
|
||||
force: bool,
|
||||
ignore_import: Option<Import<'ra>>,
|
||||
suggestion_span: Option<Span>,
|
||||
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
|
||||
self.resolve_macro_or_delegation_path(
|
||||
path,
|
||||
@@ -691,6 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
None,
|
||||
None,
|
||||
ignore_import,
|
||||
suggestion_span,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -704,6 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
deleg_impl: Option<LocalDefId>,
|
||||
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
|
||||
ignore_import: Option<Import<'ra>>,
|
||||
suggestion_span: Option<Span>,
|
||||
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
|
||||
let path_span = ast_path.span;
|
||||
let mut path = Segment::from_path(ast_path);
|
||||
@@ -768,6 +784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
kind,
|
||||
*parent_scope,
|
||||
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);
|
||||
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 +963,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,18 +583,32 @@ 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)]
|
||||
LL | struct MultipartSuggestion {
|
||||
|
|
||||
|
||||
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)]
|
||||
LL | struct MultipartSuggestion {
|
||||
|
|
||||
|
||||
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
|
||||
|
||||
19
tests/ui/macros/auxiliary/serde.rs
Normal file
19
tests/ui/macros/auxiliary/serde.rs
Normal 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!{}
|
||||
}
|
||||
33
tests/ui/macros/missing-derive-1.rs
Normal file
33
tests/ui/macros/missing-derive-1.rs
Normal 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() {}
|
||||
47
tests/ui/macros/missing-derive-1.stderr
Normal file
47
tests/ui/macros/missing-derive-1.stderr
Normal 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
|
||||
|
||||
26
tests/ui/macros/missing-derive-2.rs
Normal file
26
tests/ui/macros/missing-derive-2.rs
Normal 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() {}
|
||||
47
tests/ui/macros/missing-derive-2.stderr
Normal file
47
tests/ui/macros/missing-derive-2.stderr
Normal 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
|
||||
|
||||
24
tests/ui/macros/missing-derive-3.rs
Normal file
24
tests/ui/macros/missing-derive-3.rs
Normal 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() {}
|
||||
32
tests/ui/macros/missing-derive-3.stderr
Normal file
32
tests/ui/macros/missing-derive-3.stderr
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user