Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 7308417

Browse files
committed
Auto merge of rust-lang#125180 - mu001999-contrib:improve/macro-diag, r=<try>
Improve error message: missing `;` in macro_rules Fixes rust-lang#124968
2 parents 1189851 + 9081a66 commit 7308417

File tree

5 files changed

+62
-13
lines changed

5 files changed

+62
-13
lines changed

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub(super) fn failed_to_match_macro<'cx>(
5555

5656
let span = token.span.substitute_dummy(sp);
5757

58-
let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token));
58+
let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token, None));
5959
err.span_label(span, label);
6060
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
6161
err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
@@ -200,9 +200,15 @@ impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
200200
}
201201

202202
/// Currently used by macro_rules! compilation to extract a little information from the `Failure` case.
203-
pub struct FailureForwarder;
203+
pub struct FailureForwarder<'matcher>(Option<&'matcher Token>);
204204

205-
impl<'matcher> Tracker<'matcher> for FailureForwarder {
205+
impl<'matcher> FailureForwarder<'matcher> {
206+
pub fn new() -> Self {
207+
Self(None)
208+
}
209+
}
210+
211+
impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> {
206212
type Failure = (Token, usize, &'static str);
207213

208214
fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
@@ -212,6 +218,14 @@ impl<'matcher> Tracker<'matcher> for FailureForwarder {
212218
fn description() -> &'static str {
213219
"failure-forwarder"
214220
}
221+
222+
fn set_expect_tok(&mut self, tok: &'matcher Token) {
223+
self.0 = Some(tok);
224+
}
225+
226+
fn get_expect_tok(&self) -> Option<&'matcher Token> {
227+
self.0.clone()
228+
}
215229
}
216230

217231
pub(super) fn emit_frag_parse_err(
@@ -320,9 +334,19 @@ pub(super) fn annotate_doc_comment(dcx: &DiagCtxt, err: &mut Diag<'_>, sm: &Sour
320334

321335
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
322336
/// other tokens, this is "unexpected token...".
323-
pub(super) fn parse_failure_msg(tok: &Token) -> Cow<'static, str> {
324-
match tok.kind {
325-
token::Eof => Cow::from("unexpected end of macro invocation"),
326-
_ => Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))),
337+
pub(super) fn parse_failure_msg(tok: &Token, expect_tok: Option<&Token>) -> Cow<'static, str> {
338+
if let Some(expect_tok) = expect_tok {
339+
Cow::from(format!(
340+
"expected `{}`, found `{}`",
341+
pprust::token_to_string(expect_tok),
342+
pprust::token_to_string(tok),
343+
))
344+
} else {
345+
match tok.kind {
346+
token::Eof => Cow::from("unexpected end of macro invocation"),
347+
_ => {
348+
Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok)))
349+
}
350+
}
327351
}
328352
}

compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ impl TtParser {
541541
// The separator matches the current token. Advance past it.
542542
mp.idx += 1;
543543
self.next_mps.push(mp);
544+
} else {
545+
track.set_expect_tok(separator);
544546
}
545547
}
546548
&MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => {
@@ -632,6 +634,7 @@ impl TtParser {
632634
parser.approx_token_stream_pos(),
633635
track,
634636
);
637+
635638
if let Some(res) = res {
636639
return res;
637640
}

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ pub(super) trait Tracker<'matcher> {
167167
fn recovery() -> Recovery {
168168
Recovery::Forbidden
169169
}
170+
171+
fn set_expect_tok(&mut self, _tok: &'matcher Token) {}
172+
fn get_expect_tok(&self) -> Option<&'matcher Token> {
173+
None
174+
}
170175
}
171176

172177
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to
@@ -447,16 +452,14 @@ pub fn compile_declarative_macro(
447452
// For this we need to reclone the macro body as the previous parser consumed it.
448453
let retry_parser = create_parser();
449454

450-
let parse_result = tt_parser.parse_tt(
451-
&mut Cow::Owned(retry_parser),
452-
&argument_gram,
453-
&mut diagnostics::FailureForwarder,
454-
);
455+
let mut track = diagnostics::FailureForwarder::new();
456+
let parse_result =
457+
tt_parser.parse_tt(&mut Cow::Owned(retry_parser), &argument_gram, &mut track);
455458
let Failure((token, _, msg)) = parse_result else {
456459
unreachable!("matcher returned something other than Failure after retry");
457460
};
458461

459-
let s = parse_failure_msg(&token);
462+
let s = parse_failure_msg(&token, track.get_expect_tok());
460463
let sp = token.span.substitute_dummy(def.span);
461464
let mut err = sess.dcx().struct_span_err(sp, s);
462465
err.span_label(sp, msg);

tests/ui/macros/missing-semi.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[allow(unused_macros)]
2+
macro_rules! foo {
3+
() => {
4+
5+
}
6+
() => { //~ERROR expected `;`, found `(`
7+
8+
}
9+
}
10+
11+
fn main() {}

tests/ui/macros/missing-semi.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected `;`, found `(`
2+
--> $DIR/missing-semi.rs:6:5
3+
|
4+
LL | () => {
5+
| ^ no rules expected this token in macro call
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)