@@ -98,13 +98,18 @@ impl<'a> ParserAnyMacro<'a> {
98
98
}
99
99
}
100
100
101
+ pub ( super ) struct MacroRule {
102
+ pub ( super ) lhs : Vec < MatcherLoc > ,
103
+ lhs_span : Span ,
104
+ rhs : mbe:: TokenTree ,
105
+ }
106
+
101
107
struct MacroRulesMacroExpander {
102
108
node_id : NodeId ,
103
109
name : Ident ,
104
110
span : Span ,
105
111
transparency : Transparency ,
106
- lhses : Vec < Vec < MatcherLoc > > ,
107
- rhses : Vec < mbe:: TokenTree > ,
112
+ rules : Vec < MacroRule > ,
108
113
}
109
114
110
115
impl TTMacroExpander for MacroRulesMacroExpander {
@@ -122,10 +127,15 @@ impl TTMacroExpander for MacroRulesMacroExpander {
122
127
self . name ,
123
128
self . transparency ,
124
129
input,
125
- & self . lhses ,
126
- & self . rhses ,
130
+ & self . rules ,
127
131
) )
128
132
}
133
+
134
+ fn get_unused_rule ( & self , rule_i : usize ) -> Option < ( & Ident , Span ) > {
135
+ // If the rhs contains an invocation like `compile_error!`, don't report it as unused.
136
+ let rule = & self . rules [ rule_i] ;
137
+ if has_compile_error_macro ( & rule. rhs ) { None } else { Some ( ( & self . name , rule. lhs_span ) ) }
138
+ }
129
139
}
130
140
131
141
struct DummyExpander ( ErrorGuaranteed ) ;
@@ -184,9 +194,8 @@ impl<'matcher> Tracker<'matcher> for NoopTracker {
184
194
}
185
195
}
186
196
187
- /// Expands the rules based macro defined by `lhses` and `rhses` for a given
188
- /// input `arg`.
189
- #[ instrument( skip( cx, transparency, arg, lhses, rhses) ) ]
197
+ /// Expands the rules based macro defined by `rules` for a given input `arg`.
198
+ #[ instrument( skip( cx, transparency, arg, rules) ) ]
190
199
fn expand_macro < ' cx > (
191
200
cx : & ' cx mut ExtCtxt < ' _ > ,
192
201
sp : Span ,
@@ -195,8 +204,7 @@ fn expand_macro<'cx>(
195
204
name : Ident ,
196
205
transparency : Transparency ,
197
206
arg : TokenStream ,
198
- lhses : & [ Vec < MatcherLoc > ] ,
199
- rhses : & [ mbe:: TokenTree ] ,
207
+ rules : & [ MacroRule ] ,
200
208
) -> Box < dyn MacResult + ' cx > {
201
209
let psess = & cx. sess . psess ;
202
210
// Macros defined in the current crate have a real node id,
@@ -209,14 +217,14 @@ fn expand_macro<'cx>(
209
217
}
210
218
211
219
// Track nothing for the best performance.
212
- let try_success_result = try_match_macro ( psess, name, & arg, lhses , & mut NoopTracker ) ;
220
+ let try_success_result = try_match_macro ( psess, name, & arg, rules , & mut NoopTracker ) ;
213
221
214
222
match try_success_result {
215
- Ok ( ( i, named_matches) ) => {
216
- let mbe:: TokenTree :: Delimited ( rhs_span, _, ref rhs) = rhses [ i ] else {
223
+ Ok ( ( i, rule , named_matches) ) => {
224
+ let mbe:: TokenTree :: Delimited ( rhs_span, _, ref rhs) = rule . rhs else {
217
225
cx. dcx ( ) . span_bug ( sp, "malformed macro rhs" ) ;
218
226
} ;
219
- let arm_span = rhses [ i ] . span ( ) ;
227
+ let arm_span = rule . rhs . span ( ) ;
220
228
221
229
// rhs has holes ( `$id` and `$(...)` that need filled)
222
230
let id = cx. current_expansion . id ;
@@ -262,7 +270,7 @@ fn expand_macro<'cx>(
262
270
Err ( CanRetry :: Yes ) => {
263
271
// Retry and emit a better error.
264
272
let ( span, guar) =
265
- diagnostics:: failed_to_match_macro ( cx. psess ( ) , sp, def_span, name, arg, lhses ) ;
273
+ diagnostics:: failed_to_match_macro ( cx. psess ( ) , sp, def_span, name, arg, rules ) ;
266
274
cx. trace_macros_diag ( ) ;
267
275
DummyResult :: any ( span, guar)
268
276
}
@@ -278,14 +286,14 @@ pub(super) enum CanRetry {
278
286
/// Try expanding the macro. Returns the index of the successful arm and its named_matches if it was successful,
279
287
/// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors
280
288
/// correctly.
281
- #[ instrument( level = "debug" , skip( psess, arg, lhses , track) , fields( tracking = %T :: description( ) ) ) ]
289
+ #[ instrument( level = "debug" , skip( psess, arg, rules , track) , fields( tracking = %T :: description( ) ) ) ]
282
290
pub ( super ) fn try_match_macro < ' matcher , T : Tracker < ' matcher > > (
283
291
psess : & ParseSess ,
284
292
name : Ident ,
285
293
arg : & TokenStream ,
286
- lhses : & ' matcher [ Vec < MatcherLoc > ] ,
294
+ rules : & ' matcher [ MacroRule ] ,
287
295
track : & mut T ,
288
- ) -> Result < ( usize , NamedMatches ) , CanRetry > {
296
+ ) -> Result < ( usize , & ' matcher MacroRule , NamedMatches ) , CanRetry > {
289
297
// We create a base parser that can be used for the "black box" parts.
290
298
// Every iteration needs a fresh copy of that parser. However, the parser
291
299
// is not mutated on many of the iterations, particularly when dealing with
@@ -308,7 +316,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
308
316
let parser = parser_from_cx ( psess, arg. clone ( ) , T :: recovery ( ) ) ;
309
317
// Try each arm's matchers.
310
318
let mut tt_parser = TtParser :: new ( name) ;
311
- for ( i, lhs ) in lhses . iter ( ) . enumerate ( ) {
319
+ for ( i, rule ) in rules . iter ( ) . enumerate ( ) {
312
320
let _tracing_span = trace_span ! ( "Matching arm" , %i) ;
313
321
314
322
// Take a snapshot of the state of pre-expansion gating at this point.
@@ -317,7 +325,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
317
325
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
318
326
let mut gated_spans_snapshot = mem:: take ( & mut * psess. gated_spans . spans . borrow_mut ( ) ) ;
319
327
320
- let result = tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , lhs, track) ;
328
+ let result = tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , & rule . lhs , track) ;
321
329
322
330
track. after_arm ( & result) ;
323
331
@@ -328,7 +336,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
328
336
// Merge the gated spans from parsing the matcher with the preexisting ones.
329
337
psess. gated_spans . merge ( gated_spans_snapshot) ;
330
338
331
- return Ok ( ( i, named_matches) ) ;
339
+ return Ok ( ( i, rule , named_matches) ) ;
332
340
}
333
341
Failure ( _) => {
334
342
trace ! ( "Failed to match arm, trying the next one" ) ;
@@ -364,7 +372,7 @@ pub fn compile_declarative_macro(
364
372
span : Span ,
365
373
node_id : NodeId ,
366
374
edition : Edition ,
367
- ) -> ( SyntaxExtension , Vec < ( usize , Span ) > ) {
375
+ ) -> ( SyntaxExtension , usize ) {
368
376
let mk_syn_ext = |expander| {
369
377
SyntaxExtension :: new (
370
378
sess,
@@ -377,7 +385,7 @@ pub fn compile_declarative_macro(
377
385
node_id != DUMMY_NODE_ID ,
378
386
)
379
387
} ;
380
- let dummy_syn_ext = |guar| ( mk_syn_ext ( Arc :: new ( DummyExpander ( guar) ) ) , Vec :: new ( ) ) ;
388
+ let dummy_syn_ext = |guar| ( mk_syn_ext ( Arc :: new ( DummyExpander ( guar) ) ) , 0 ) ;
381
389
382
390
let macro_rules = macro_def. macro_rules ;
383
391
let exp_sep = if macro_rules { exp ! ( Semi ) } else { exp ! ( Comma ) } ;
@@ -389,8 +397,7 @@ pub fn compile_declarative_macro(
389
397
let mut guar = None ;
390
398
let mut check_emission = |ret : Result < ( ) , ErrorGuaranteed > | guar = guar. or ( ret. err ( ) ) ;
391
399
392
- let mut lhses = Vec :: new ( ) ;
393
- let mut rhses = Vec :: new ( ) ;
400
+ let mut rules = Vec :: new ( ) ;
394
401
395
402
while p. token != token:: Eof {
396
403
let lhs_tt = p. parse_token_tree ( ) ;
@@ -415,8 +422,15 @@ pub fn compile_declarative_macro(
415
422
let rhs_tt = parse_one_tt ( rhs_tt, RulePart :: Body , sess, node_id, features, edition) ;
416
423
check_emission ( check_rhs ( sess, & rhs_tt) ) ;
417
424
check_emission ( macro_check:: check_meta_variables ( & sess. psess , node_id, & lhs_tt, & rhs_tt) ) ;
418
- lhses. push ( lhs_tt) ;
419
- rhses. push ( rhs_tt) ;
425
+ let lhs_span = lhs_tt. span ( ) ;
426
+ // Convert the lhs into `MatcherLoc` form, which is better for doing the
427
+ // actual matching.
428
+ let lhs = if let mbe:: TokenTree :: Delimited ( .., delimited) = lhs_tt {
429
+ mbe:: macro_parser:: compute_locs ( & delimited. tts )
430
+ } else {
431
+ return dummy_syn_ext ( guar. unwrap ( ) ) ;
432
+ } ;
433
+ rules. push ( MacroRule { lhs, lhs_span, rhs : rhs_tt } ) ;
420
434
if p. token == token:: Eof {
421
435
break ;
422
436
}
@@ -425,7 +439,7 @@ pub fn compile_declarative_macro(
425
439
}
426
440
}
427
441
428
- if lhses . is_empty ( ) {
442
+ if rules . is_empty ( ) {
429
443
let guar = sess. dcx ( ) . span_err ( span, "macros must contain at least one rule" ) ;
430
444
return dummy_syn_ext ( guar) ;
431
445
}
@@ -439,48 +453,12 @@ pub fn compile_declarative_macro(
439
453
return dummy_syn_ext ( guar) ;
440
454
}
441
455
442
- // Compute the spans of the macro rules for unused rule linting.
443
- // Also, we are only interested in non-foreign macros.
444
- let rule_spans = if node_id != DUMMY_NODE_ID {
445
- lhses
446
- . iter ( )
447
- . zip ( rhses. iter ( ) )
448
- . enumerate ( )
449
- // If the rhs contains an invocation like compile_error!,
450
- // don't consider the rule for the unused rule lint.
451
- . filter ( |( _idx, ( _lhs, rhs) ) | !has_compile_error_macro ( rhs) )
452
- // We only take the span of the lhs here,
453
- // so that the spans of created warnings are smaller.
454
- . map ( |( idx, ( lhs, _rhs) ) | ( idx, lhs. span ( ) ) )
455
- . collect :: < Vec < _ > > ( )
456
- } else {
457
- Vec :: new ( )
458
- } ;
456
+ // Return the number of rules for unused rule linting, if this is a local macro.
457
+ let nrules = if node_id != DUMMY_NODE_ID { rules. len ( ) } else { 0 } ;
459
458
460
- // Convert the lhses into `MatcherLoc` form, which is better for doing the
461
- // actual matching.
462
- let lhses = lhses
463
- . iter ( )
464
- . map ( |lhs| {
465
- // Ignore the delimiters around the matcher.
466
- match lhs {
467
- mbe:: TokenTree :: Delimited ( .., delimited) => {
468
- mbe:: macro_parser:: compute_locs ( & delimited. tts )
469
- }
470
- _ => sess. dcx ( ) . span_bug ( span, "malformed macro lhs" ) ,
471
- }
472
- } )
473
- . collect ( ) ;
474
-
475
- let expander = Arc :: new ( MacroRulesMacroExpander {
476
- name : ident,
477
- span,
478
- node_id,
479
- transparency,
480
- lhses,
481
- rhses,
482
- } ) ;
483
- ( mk_syn_ext ( expander) , rule_spans)
459
+ let expander =
460
+ Arc :: new ( MacroRulesMacroExpander { name : ident, span, node_id, transparency, rules } ) ;
461
+ ( mk_syn_ext ( expander) , nrules)
484
462
}
485
463
486
464
fn check_lhs_nt_follows (
0 commit comments