@@ -332,7 +332,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
332332 ( * * tt) . clone ( )
333333 }
334334 _ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
335- } ) . collect ( )
335+ } ) . collect :: < Vec < TokenTree > > ( )
336336 }
337337 _ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
338338 } ;
@@ -351,6 +351,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
351351 valid &= check_rhs ( sess, rhs) ;
352352 }
353353
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+
354359 let exp: Box < _ > = Box :: new ( MacroRulesMacroExpander {
355360 name : def. ident ,
356361 imported_from : def. imported_from ,
@@ -377,6 +382,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
377382 // after parsing/expansion. we can report every error in every macro this way.
378383}
379384
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+
380417fn check_rhs ( sess : & ParseSess , rhs : & TokenTree ) -> bool {
381418 match * rhs {
382419 TokenTree :: Delimited ( ..) => return true ,
0 commit comments