@@ -332,7 +332,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
332
332
( * * tt) . clone ( )
333
333
}
334
334
_ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
335
- } ) . collect ( )
335
+ } ) . collect :: < Vec < TokenTree > > ( )
336
336
}
337
337
_ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
338
338
} ;
@@ -351,6 +351,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
351
351
valid &= check_rhs ( sess, rhs) ;
352
352
}
353
353
354
+ // don't abort iteration early, so that errors for multiple lhses can be reported
355
+ for lhs in & lhses {
356
+ valid &= check_lhs_no_empty_seq ( sess, & [ lhs. clone ( ) ] )
357
+ }
358
+
354
359
let exp: Box < _ > = Box :: new ( MacroRulesMacroExpander {
355
360
name : def. ident ,
356
361
imported_from : def. imported_from ,
@@ -377,6 +382,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
377
382
// after parsing/expansion. we can report every error in every macro this way.
378
383
}
379
384
385
+ /// Check that the lhs contains no repetition which could match an empty token
386
+ /// tree, because then the matcher would hang indefinitely.
387
+ fn check_lhs_no_empty_seq ( sess : & ParseSess , tts : & [ TokenTree ] ) -> bool {
388
+ for tt in tts {
389
+ match * tt {
390
+ TokenTree :: Token ( _, _) => ( ) ,
391
+ TokenTree :: Delimited ( _, ref del) => if !check_lhs_no_empty_seq ( sess, & del. tts ) {
392
+ return false ;
393
+ } ,
394
+ TokenTree :: Sequence ( span, ref seq) => {
395
+ if seq. separator . is_none ( ) {
396
+ if seq. tts . iter ( ) . all ( |seq_tt| {
397
+ match * seq_tt {
398
+ TokenTree :: Sequence ( _, ref sub_seq) =>
399
+ sub_seq. op == tokenstream:: KleeneOp :: ZeroOrMore ,
400
+ _ => false ,
401
+ }
402
+ } ) {
403
+ sess. span_diagnostic . span_err ( span, "repetition matches empty token tree" ) ;
404
+ return false ;
405
+ }
406
+ }
407
+ if !check_lhs_no_empty_seq ( sess, & seq. tts ) {
408
+ return false ;
409
+ }
410
+ }
411
+ }
412
+ }
413
+
414
+ true
415
+ }
416
+
380
417
fn check_rhs ( sess : & ParseSess , rhs : & TokenTree ) -> bool {
381
418
match * rhs {
382
419
TokenTree :: Delimited ( ..) => return true ,
0 commit comments