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_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 ¯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(
|
pub(crate) fn add_typo_suggestion(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>)>,
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
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]
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user