@@ -98,13 +98,18 @@ impl<'a> ParserAnyMacro<'a> {
9898 }
9999}
100100
101+ pub ( super ) struct MacroRule {
102+ pub ( super ) lhs : Vec < MatcherLoc > ,
103+ lhs_span : Span ,
104+ rhs : mbe:: TokenTree ,
105+ }
106+
101107struct MacroRulesMacroExpander {
102108 node_id : NodeId ,
103109 name : Ident ,
104110 span : Span ,
105111 transparency : Transparency ,
106- lhses : Vec < Vec < MatcherLoc > > ,
107- rhses : Vec < mbe:: TokenTree > ,
112+ rules : Vec < MacroRule > ,
108113}
109114
110115impl TTMacroExpander for MacroRulesMacroExpander {
@@ -122,10 +127,15 @@ impl TTMacroExpander for MacroRulesMacroExpander {
122127 self . name ,
123128 self . transparency ,
124129 input,
125- & self . lhses ,
126- & self . rhses ,
130+ & self . rules ,
127131 ) )
128132 }
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+ }
129139}
130140
131141struct DummyExpander ( ErrorGuaranteed ) ;
@@ -184,9 +194,8 @@ impl<'matcher> Tracker<'matcher> for NoopTracker {
184194 }
185195}
186196
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) ) ]
190199fn expand_macro < ' cx > (
191200 cx : & ' cx mut ExtCtxt < ' _ > ,
192201 sp : Span ,
@@ -195,8 +204,7 @@ fn expand_macro<'cx>(
195204 name : Ident ,
196205 transparency : Transparency ,
197206 arg : TokenStream ,
198- lhses : & [ Vec < MatcherLoc > ] ,
199- rhses : & [ mbe:: TokenTree ] ,
207+ rules : & [ MacroRule ] ,
200208) -> Box < dyn MacResult + ' cx > {
201209 let psess = & cx. sess . psess ;
202210 // Macros defined in the current crate have a real node id,
@@ -209,14 +217,14 @@ fn expand_macro<'cx>(
209217 }
210218
211219 // 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 ) ;
213221
214222 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 {
217225 cx. dcx ( ) . span_bug ( sp, "malformed macro rhs" ) ;
218226 } ;
219- let arm_span = rhses [ i ] . span ( ) ;
227+ let arm_span = rule . rhs . span ( ) ;
220228
221229 // rhs has holes ( `$id` and `$(...)` that need filled)
222230 let id = cx. current_expansion . id ;
@@ -262,7 +270,7 @@ fn expand_macro<'cx>(
262270 Err ( CanRetry :: Yes ) => {
263271 // Retry and emit a better error.
264272 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 ) ;
266274 cx. trace_macros_diag ( ) ;
267275 DummyResult :: any ( span, guar)
268276 }
@@ -278,14 +286,14 @@ pub(super) enum CanRetry {
278286/// Try expanding the macro. Returns the index of the successful arm and its named_matches if it was successful,
279287/// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors
280288/// 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( ) ) ) ]
282290pub ( super ) fn try_match_macro < ' matcher , T : Tracker < ' matcher > > (
283291 psess : & ParseSess ,
284292 name : Ident ,
285293 arg : & TokenStream ,
286- lhses : & ' matcher [ Vec < MatcherLoc > ] ,
294+ rules : & ' matcher [ MacroRule ] ,
287295 track : & mut T ,
288- ) -> Result < ( usize , NamedMatches ) , CanRetry > {
296+ ) -> Result < ( usize , & ' matcher MacroRule , NamedMatches ) , CanRetry > {
289297 // We create a base parser that can be used for the "black box" parts.
290298 // Every iteration needs a fresh copy of that parser. However, the parser
291299 // 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>>(
308316 let parser = parser_from_cx ( psess, arg. clone ( ) , T :: recovery ( ) ) ;
309317 // Try each arm's matchers.
310318 let mut tt_parser = TtParser :: new ( name) ;
311- for ( i, lhs ) in lhses . iter ( ) . enumerate ( ) {
319+ for ( i, rule ) in rules . iter ( ) . enumerate ( ) {
312320 let _tracing_span = trace_span ! ( "Matching arm" , %i) ;
313321
314322 // 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>>(
317325 // are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
318326 let mut gated_spans_snapshot = mem:: take ( & mut * psess. gated_spans . spans . borrow_mut ( ) ) ;
319327
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) ;
321329
322330 track. after_arm ( & result) ;
323331
@@ -328,7 +336,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
328336 // Merge the gated spans from parsing the matcher with the preexisting ones.
329337 psess. gated_spans . merge ( gated_spans_snapshot) ;
330338
331- return Ok ( ( i, named_matches) ) ;
339+ return Ok ( ( i, rule , named_matches) ) ;
332340 }
333341 Failure ( _) => {
334342 trace ! ( "Failed to match arm, trying the next one" ) ;
@@ -364,7 +372,7 @@ pub fn compile_declarative_macro(
364372 span : Span ,
365373 node_id : NodeId ,
366374 edition : Edition ,
367- ) -> ( SyntaxExtension , Vec < ( usize , Span ) > ) {
375+ ) -> ( SyntaxExtension , usize ) {
368376 let mk_syn_ext = |expander| {
369377 SyntaxExtension :: new (
370378 sess,
@@ -377,7 +385,7 @@ pub fn compile_declarative_macro(
377385 node_id != DUMMY_NODE_ID ,
378386 )
379387 } ;
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 ) ;
381389
382390 let macro_rules = macro_def. macro_rules ;
383391 let exp_sep = if macro_rules { exp ! ( Semi ) } else { exp ! ( Comma ) } ;
@@ -389,8 +397,7 @@ pub fn compile_declarative_macro(
389397 let mut guar = None ;
390398 let mut check_emission = |ret : Result < ( ) , ErrorGuaranteed > | guar = guar. or ( ret. err ( ) ) ;
391399
392- let mut lhses = Vec :: new ( ) ;
393- let mut rhses = Vec :: new ( ) ;
400+ let mut rules = Vec :: new ( ) ;
394401
395402 while p. token != token:: Eof {
396403 let lhs_tt = p. parse_token_tree ( ) ;
@@ -415,8 +422,15 @@ pub fn compile_declarative_macro(
415422 let rhs_tt = parse_one_tt ( rhs_tt, RulePart :: Body , sess, node_id, features, edition) ;
416423 check_emission ( check_rhs ( sess, & rhs_tt) ) ;
417424 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 } ) ;
420434 if p. token == token:: Eof {
421435 break ;
422436 }
@@ -425,7 +439,7 @@ pub fn compile_declarative_macro(
425439 }
426440 }
427441
428- if lhses . is_empty ( ) {
442+ if rules . is_empty ( ) {
429443 let guar = sess. dcx ( ) . span_err ( span, "macros must contain at least one rule" ) ;
430444 return dummy_syn_ext ( guar) ;
431445 }
@@ -439,48 +453,12 @@ pub fn compile_declarative_macro(
439453 return dummy_syn_ext ( guar) ;
440454 }
441455
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 } ;
459458
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)
484462}
485463
486464fn check_lhs_nt_follows (
0 commit comments