@@ -141,31 +141,40 @@ fn trace_macros_note(cx_expansions: &mut FxIndexMap<Span, Vec<String>>, sp: Span
141
141
}
142
142
143
143
pub ( super ) trait Tracker < ' matcher > {
144
+ /// The contents of `ParseResult::Failure`.
145
+ type Failure ;
146
+
147
+ /// Arm failed to match. If the token is `token::Eof`, it indicates an unexpected
148
+ /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
149
+ /// The usize is the approximate position of the token in the input token stream.
150
+ fn build_failure ( tok : Token , position : usize , msg : & ' static str ) -> Self :: Failure ;
151
+
144
152
/// This is called before trying to match next MatcherLoc on the current token.
145
- fn before_match_loc ( & mut self , parser : & TtParser , matcher : & ' matcher MatcherLoc ) ;
153
+ fn before_match_loc ( & mut self , _parser : & TtParser , _matcher : & ' matcher MatcherLoc ) { }
146
154
147
155
/// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
148
156
/// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
149
- fn after_arm ( & mut self , result : & NamedParseResult ) ;
157
+ fn after_arm ( & mut self , _result : & NamedParseResult < Self :: Failure > ) { }
150
158
151
159
/// For tracing.
152
160
fn description ( ) -> & ' static str ;
153
161
154
- fn recovery ( ) -> Recovery ;
162
+ fn recovery ( ) -> Recovery {
163
+ Recovery :: Forbidden
164
+ }
155
165
}
156
166
157
167
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
158
168
pub ( super ) struct NoopTracker ;
159
169
160
170
impl < ' matcher > Tracker < ' matcher > for NoopTracker {
161
- fn before_match_loc ( & mut self , _: & TtParser , _: & ' matcher MatcherLoc ) { }
162
- fn after_arm ( & mut self , _: & NamedParseResult ) { }
171
+ type Failure = ( ) ;
172
+
173
+ fn build_failure ( _tok : Token , _position : usize , _msg : & ' static str ) -> Self :: Failure { }
174
+
163
175
fn description ( ) -> & ' static str {
164
176
"none"
165
177
}
166
- fn recovery ( ) -> Recovery {
167
- Recovery :: Forbidden
168
- }
169
178
}
170
179
171
180
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
@@ -326,8 +335,8 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
326
335
327
336
return Ok ( ( i, named_matches) ) ;
328
337
}
329
- Failure ( _, reached_position , _ ) => {
330
- trace ! ( %reached_position , "Failed to match arm, trying the next one" ) ;
338
+ Failure ( _) => {
339
+ trace ! ( "Failed to match arm, trying the next one" ) ;
331
340
// Try the next arm.
332
341
}
333
342
Error ( _, _) => {
@@ -381,11 +390,13 @@ pub fn compile_declarative_macro(
381
390
let rhs_nm = Ident :: new ( sym:: rhs, def. span ) ;
382
391
let tt_spec = Some ( NonterminalKind :: TT ) ;
383
392
384
- // Parse the macro_rules! invocation
385
- let ( macro_rules, body) = match & def. kind {
386
- ast:: ItemKind :: MacroDef ( def) => ( def. macro_rules , def. body . tokens . clone ( ) ) ,
393
+ let macro_def = match & def. kind {
394
+ ast:: ItemKind :: MacroDef ( def) => def,
387
395
_ => unreachable ! ( ) ,
388
396
} ;
397
+ let macro_rules = macro_def. macro_rules ;
398
+
399
+ // Parse the macro_rules! invocation
389
400
390
401
// The pattern that macro_rules matches.
391
402
// The grammar for macro_rules! is:
@@ -426,13 +437,32 @@ pub fn compile_declarative_macro(
426
437
// Convert it into `MatcherLoc` form.
427
438
let argument_gram = mbe:: macro_parser:: compute_locs ( & argument_gram) ;
428
439
429
- let parser = Parser :: new ( & sess. parse_sess , body, true , rustc_parse:: MACRO_ARGUMENTS ) ;
440
+ let create_parser = || {
441
+ let body = macro_def. body . tokens . clone ( ) ;
442
+ Parser :: new ( & sess. parse_sess , body, true , rustc_parse:: MACRO_ARGUMENTS )
443
+ } ;
444
+
445
+ let parser = create_parser ( ) ;
430
446
let mut tt_parser =
431
447
TtParser :: new ( Ident :: with_dummy_span ( if macro_rules { kw:: MacroRules } else { kw:: Macro } ) ) ;
432
448
let argument_map =
433
449
match tt_parser. parse_tt ( & mut Cow :: Owned ( parser) , & argument_gram, & mut NoopTracker ) {
434
450
Success ( m) => m,
435
- Failure ( token, _, msg) => {
451
+ Failure ( ( ) ) => {
452
+ // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it with another one
453
+ // that gives us the information we need.
454
+ // For this we need to reclone the macro body as the previous parser consumed it.
455
+ let retry_parser = create_parser ( ) ;
456
+
457
+ let parse_result = tt_parser. parse_tt (
458
+ & mut Cow :: Owned ( retry_parser) ,
459
+ & argument_gram,
460
+ & mut diagnostics:: FailureForwarder ,
461
+ ) ;
462
+ let Failure ( ( token, _, msg) ) = parse_result else {
463
+ unreachable ! ( "matcher returned something other than Failure after retry" ) ;
464
+ } ;
465
+
436
466
let s = parse_failure_msg ( & token) ;
437
467
let sp = token. span . substitute_dummy ( def. span ) ;
438
468
let mut err = sess. parse_sess . span_diagnostic . struct_span_err ( sp, & s) ;
0 commit comments