Skip to content

Commit 38c940e

Browse files
committed
mbe: Emit an error if an invoked macro has no invocation rules
Add a corresponding test.
1 parent 612969e commit 38c940e

File tree

3 files changed

+28
-4
lines changed

3 files changed

+28
-4
lines changed

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_macros::Subdiagnostic;
77
use rustc_parse::parser::{Parser, Recovery, token_descr};
88
use rustc_session::parse::ParseSess;
99
use rustc_span::source_map::SourceMap;
10-
use rustc_span::{ErrorGuaranteed, Ident, Span};
10+
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span};
1111
use tracing::debug;
1212

1313
use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx};
@@ -25,6 +25,12 @@ pub(super) fn failed_to_match_macro(
2525
rules: &[MacroRule],
2626
) -> (Span, ErrorGuaranteed) {
2727
debug!("failed to match macro");
28+
let def_head_span = if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
29+
psess.source_map().guess_head_span(def_span)
30+
} else {
31+
DUMMY_SP
32+
};
33+
2834
// An error occurred, try the expansion again, tracking the expansion closely for better
2935
// diagnostics.
3036
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
@@ -47,15 +53,22 @@ pub(super) fn failed_to_match_macro(
4753

4854
let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
4955
else {
56+
if !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) {
57+
let mut err = psess.dcx().struct_span_err(sp, "invoked macro has no invocation rules");
58+
if !def_head_span.is_dummy() {
59+
err.span_label(def_head_span, "this macro has no rules to invoke");
60+
}
61+
return (sp, err.emit());
62+
}
5063
return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
5164
};
5265

5366
let span = token.span.substitute_dummy(sp);
5467

5568
let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None));
5669
err.span_label(span, label);
57-
if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
58-
err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro");
70+
if !def_head_span.is_dummy() {
71+
err.span_label(def_head_span, "when calling this macro");
5972
}
6073

6174
annotate_doc_comment(&mut err, psess.source_map(), span);

tests/ui/macros/macro-rules-attr-error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ macro_rules! local_attr {
1010
fn main() {
1111
#[local_attr]
1212
struct S;
13+
14+
local_attr!(arg); //~ ERROR: invoked macro has no invocation rules
1315
}

tests/ui/macros/macro-rules-attr-error.stderr

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,14 @@ LL | #[local_attr]
99
|
1010
= note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
1111

12-
error: aborting due to 1 previous error
12+
error: invoked macro has no invocation rules
13+
--> $DIR/macro-rules-attr-error.rs:14:5
14+
|
15+
LL | macro_rules! local_attr {
16+
| ----------------------- this macro has no rules to invoke
17+
...
18+
LL | local_attr!(arg);
19+
| ^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 2 previous errors
1322

0 commit comments

Comments
 (0)