Detect and report macro kind mismatches early, and more precisely
This eliminates the case in `failed_to_match_macro` to check for a function-like invocation of a macro with no function-like rules. Instead, macro kind mismatches now result in an unresolved macro, and we detect this case in `unresolved_macro_suggestions`, which now carefully distinguishes between a kind mismatch and other errors. This also handles cases of forward-referenced attributes and cyclic attributes. Expand test coverage to include all of these cases.
This commit is contained in:
parent
c81fcaca1c
commit
ba231db3f3
6 changed files with 108 additions and 29 deletions
|
|
@ -58,18 +58,6 @@ pub(super) fn failed_to_match_macro(
|
|||
|
||||
let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
|
||||
else {
|
||||
// FIXME: we should report this at macro resolution time, as we do for
|
||||
// `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a
|
||||
// Def.
|
||||
if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) {
|
||||
let msg = format!("macro has no rules for function-like invocation `{name}!`");
|
||||
let mut err = psess.dcx().struct_span_err(sp, msg);
|
||||
if !def_head_span.is_dummy() {
|
||||
let msg = "this macro has no rules for function-like invocation";
|
||||
err.span_label(def_head_span, msg);
|
||||
}
|
||||
return (sp, err.emit());
|
||||
}
|
||||
return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -242,6 +242,9 @@ resolve_lowercase_self =
|
|||
attempt to use a non-constant value in a constant
|
||||
.suggestion = try using `Self`
|
||||
|
||||
resolve_macro_cannot_use_as_fn_like =
|
||||
`{$ident}` exists, but has no rules for function-like invocation
|
||||
|
||||
resolve_macro_cannot_use_as_attr =
|
||||
`{$ident}` exists, but has no `attr` rules
|
||||
|
||||
|
|
|
|||
|
|
@ -1555,11 +1555,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if let Some((def_id, unused_ident)) = unused_macro {
|
||||
let scope = self.local_macro_def_scopes[&def_id];
|
||||
let parent_nearest = parent_scope.module.nearest_parent_mod();
|
||||
if Some(parent_nearest) == scope.opt_def_id() {
|
||||
let unused_macro_kinds = self.local_macro_map[def_id].ext.macro_kinds();
|
||||
if !unused_macro_kinds.contains(macro_kind.into()) {
|
||||
match macro_kind {
|
||||
MacroKind::Bang => {
|
||||
err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
|
||||
err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
|
||||
err.subdiagnostic(MacroRulesNot::Func { span: unused_ident.span, ident });
|
||||
}
|
||||
MacroKind::Attr => {
|
||||
err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
|
||||
|
|
@ -1568,14 +1568,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
|
||||
err.subdiagnostic(AddedMacroUse);
|
||||
return;
|
||||
if Some(parent_nearest) == scope.opt_def_id() {
|
||||
err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
|
||||
err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ident.name == kw::Default
|
||||
|
|
@ -1651,6 +1650,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
err.subdiagnostic(note);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
|
||||
err.subdiagnostic(AddedMacroUse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Given an attribute macro that failed to be resolved, look for `derive` macros that could
|
||||
|
|
|
|||
|
|
@ -672,6 +672,12 @@ pub(crate) struct MacroSuggMovePosition {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum MacroRulesNot {
|
||||
#[label(resolve_macro_cannot_use_as_fn_like)]
|
||||
Func {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
},
|
||||
#[label(resolve_macro_cannot_use_as_attr)]
|
||||
Attr {
|
||||
#[primary_span]
|
||||
|
|
|
|||
|
|
@ -7,9 +7,46 @@ macro_rules! local_attr {
|
|||
//~^^ ERROR: local_attr
|
||||
}
|
||||
|
||||
//~v NOTE: `fn_only` exists, but has no `attr` rules
|
||||
macro_rules! fn_only {
|
||||
{} => {}
|
||||
}
|
||||
|
||||
//~v NOTE: `attr_only` exists, but has no rules for function-like invocation
|
||||
macro_rules! attr_only {
|
||||
attr() {} => {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
//~v NOTE: in this expansion of #[local_attr]
|
||||
#[local_attr]
|
||||
struct S;
|
||||
|
||||
local_attr!(arg); //~ ERROR: macro has no rules for function-like invocation
|
||||
//~vv ERROR: cannot find macro `local_attr` in this scope
|
||||
//~| NOTE: `local_attr` is in scope, but it is an attribute
|
||||
local_attr!(arg);
|
||||
|
||||
//~v ERROR: cannot find attribute `fn_only` in this scope
|
||||
#[fn_only]
|
||||
struct S;
|
||||
|
||||
attr_only!(); //~ ERROR: cannot find macro `attr_only` in this scope
|
||||
}
|
||||
|
||||
//~vv ERROR: cannot find attribute `forward_referenced_attr` in this scope
|
||||
//~| NOTE: consider moving the definition of `forward_referenced_attr` before this call
|
||||
#[forward_referenced_attr]
|
||||
struct S;
|
||||
|
||||
//~v NOTE: a macro with the same name exists, but it appears later
|
||||
macro_rules! forward_referenced_attr {
|
||||
attr() {} => {}
|
||||
}
|
||||
|
||||
//~vv ERROR: cannot find attribute `cyclic_attr` in this scope
|
||||
//~| NOTE: consider moving the definition of `cyclic_attr` before this call
|
||||
#[cyclic_attr]
|
||||
//~v NOTE: a macro with the same name exists, but it appears later
|
||||
macro_rules! cyclic_attr {
|
||||
attr() {} => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,55 @@ LL | #[local_attr]
|
|||
|
|
||||
= note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: macro has no rules for function-like invocation `local_attr!`
|
||||
--> $DIR/macro-rules-attr-error.rs:14:5
|
||||
error: cannot find macro `local_attr` in this scope
|
||||
--> $DIR/macro-rules-attr-error.rs:27:5
|
||||
|
|
||||
LL | macro_rules! local_attr {
|
||||
| ----------------------- this macro has no rules for function-like invocation
|
||||
...
|
||||
LL | local_attr!(arg);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `local_attr` is in scope, but it is an attribute: `#[local_attr]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: cannot find attribute `fn_only` in this scope
|
||||
--> $DIR/macro-rules-attr-error.rs:30:7
|
||||
|
|
||||
LL | macro_rules! fn_only {
|
||||
| ------- `fn_only` exists, but has no `attr` rules
|
||||
...
|
||||
LL | #[fn_only]
|
||||
| ^^^^^^^
|
||||
|
||||
error: cannot find macro `attr_only` in this scope
|
||||
--> $DIR/macro-rules-attr-error.rs:33:5
|
||||
|
|
||||
LL | macro_rules! attr_only {
|
||||
| --------- `attr_only` exists, but has no rules for function-like invocation
|
||||
...
|
||||
LL | attr_only!();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: cannot find attribute `forward_referenced_attr` in this scope
|
||||
--> $DIR/macro-rules-attr-error.rs:38:3
|
||||
|
|
||||
LL | #[forward_referenced_attr]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ consider moving the definition of `forward_referenced_attr` before this call
|
||||
|
|
||||
note: a macro with the same name exists, but it appears later
|
||||
--> $DIR/macro-rules-attr-error.rs:42:14
|
||||
|
|
||||
LL | macro_rules! forward_referenced_attr {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: cannot find attribute `cyclic_attr` in this scope
|
||||
--> $DIR/macro-rules-attr-error.rs:48:3
|
||||
|
|
||||
LL | #[cyclic_attr]
|
||||
| ^^^^^^^^^^^ consider moving the definition of `cyclic_attr` before this call
|
||||
|
|
||||
note: a macro with the same name exists, but it appears later
|
||||
--> $DIR/macro-rules-attr-error.rs:50:14
|
||||
|
|
||||
LL | macro_rules! cyclic_attr {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue