@@ -22,7 +22,7 @@ use rustc_lint_defs::builtin::{
22
22
RUST_2021_INCOMPATIBLE_OR_PATTERNS , SEMICOLON_IN_EXPRESSIONS_FROM_MACROS ,
23
23
} ;
24
24
use rustc_lint_defs:: BuiltinLintDiagnostics ;
25
- use rustc_parse:: parser:: Parser ;
25
+ use rustc_parse:: parser:: { Parser , Recovery } ;
26
26
use rustc_session:: parse:: ParseSess ;
27
27
use rustc_session:: Session ;
28
28
use rustc_span:: edition:: Edition ;
@@ -219,6 +219,8 @@ pub(super) trait Tracker<'matcher> {
219
219
220
220
/// For tracing.
221
221
fn description ( ) -> & ' static str ;
222
+
223
+ fn recovery ( ) -> Recovery ;
222
224
}
223
225
224
226
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
@@ -230,6 +232,9 @@ impl<'matcher> Tracker<'matcher> for NoopTracker {
230
232
fn description ( ) -> & ' static str {
231
233
"none"
232
234
}
235
+ fn recovery ( ) -> Recovery {
236
+ Recovery :: Forbidden
237
+ }
233
238
}
234
239
235
240
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
@@ -330,15 +335,20 @@ fn expand_macro<'cx>(
330
335
let mut tracker = CollectTrackerAndEmitter :: new ( cx, sp) ;
331
336
332
337
let try_success_result = try_match_macro ( sess, name, & arg, lhses, & mut tracker) ;
333
- assert ! ( try_success_result. is_err( ) , "Macro matching returned a success on the second try" ) ;
338
+
339
+ if try_success_result. is_ok ( ) {
340
+ // Nonterminal parser recovery might turn failed matches into successful ones,
341
+ // but for that it must have emitted an error already
342
+ tracker. cx . sess . delay_span_bug ( sp, "Macro matching returned a success on the second try" ) ;
343
+ }
334
344
335
345
if let Some ( result) = tracker. result {
336
346
// An irrecoverable error occurred and has been emitted.
337
347
return result;
338
348
}
339
349
340
350
let Some ( ( token, label, remaining_matcher) ) = tracker. best_failure else {
341
- return tracker . result . expect ( "must have encountered Error or ErrorReported" ) ;
351
+ return DummyResult :: any ( sp ) ;
342
352
} ;
343
353
344
354
let span = token. span . substitute_dummy ( sp) ;
@@ -360,7 +370,7 @@ fn expand_macro<'cx>(
360
370
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
361
371
if let Some ( ( arg, comma_span) ) = arg. add_comma ( ) {
362
372
for lhs in lhses {
363
- let parser = parser_from_cx ( sess, arg. clone ( ) ) ;
373
+ let parser = parser_from_cx ( sess, arg. clone ( ) , Recovery :: Allowed ) ;
364
374
let mut tt_parser = TtParser :: new ( name) ;
365
375
366
376
if let Success ( _) =
@@ -406,7 +416,12 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
406
416
fn after_arm ( & mut self , result : & NamedParseResult ) {
407
417
match result {
408
418
Success ( _) => {
409
- unreachable ! ( "should not collect detailed info for successful macro match" ) ;
419
+ // Nonterminal parser recovery might turn failed matches into successful ones,
420
+ // but for that it must have emitted an error already
421
+ self . cx . sess . delay_span_bug (
422
+ self . root_span ,
423
+ "should not collect detailed info for successful macro match" ,
424
+ ) ;
410
425
}
411
426
Failure ( token, msg) => match self . best_failure {
412
427
Some ( ( ref best_token, _, _) ) if best_token. span . lo ( ) >= token. span . lo ( ) => { }
@@ -432,6 +447,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
432
447
fn description ( ) -> & ' static str {
433
448
"detailed"
434
449
}
450
+
451
+ fn recovery ( ) -> Recovery {
452
+ Recovery :: Allowed
453
+ }
435
454
}
436
455
437
456
impl < ' a , ' cx > CollectTrackerAndEmitter < ' a , ' cx , ' _ > {
@@ -477,7 +496,7 @@ fn try_match_macro<'matcher, T: Tracker<'matcher>>(
477
496
// 68836 suggests a more comprehensive but more complex change to deal with
478
497
// this situation.)
479
498
// FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
480
- let parser = parser_from_cx ( sess, arg. clone ( ) ) ;
499
+ let parser = parser_from_cx ( sess, arg. clone ( ) , T :: recovery ( ) ) ;
481
500
// Try each arm's matchers.
482
501
let mut tt_parser = TtParser :: new ( name) ;
483
502
for ( i, lhs) in lhses. iter ( ) . enumerate ( ) {
@@ -1559,8 +1578,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
1559
1578
}
1560
1579
}
1561
1580
1562
- fn parser_from_cx ( sess : & ParseSess , tts : TokenStream ) -> Parser < ' _ > {
1563
- Parser :: new ( sess, tts, true , rustc_parse:: MACRO_ARGUMENTS )
1581
+ fn parser_from_cx ( sess : & ParseSess , tts : TokenStream , recovery : Recovery ) -> Parser < ' _ > {
1582
+ Parser :: new ( sess, tts, true , rustc_parse:: MACRO_ARGUMENTS ) . recovery ( recovery )
1564
1583
}
1565
1584
1566
1585
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
0 commit comments