@@ -243,7 +243,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
243243 ( * * tt) . clone ( )
244244 }
245245 _ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
246- } ) . collect ( )
246+ } ) . collect :: < Vec < TokenTree > > ( )
247247 }
248248 _ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
249249 } ;
@@ -262,6 +262,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
262262 valid &= check_rhs ( sess, rhs) ;
263263 }
264264
265+ // don't abort iteration early, so that errors for multiple lhses can be reported
266+ for lhs in & lhses {
267+ valid &= check_lhs_no_empty_seq ( sess, & [ lhs. clone ( ) ] )
268+ }
269+
265270 let exp: Box < _ > = Box :: new ( MacroRulesMacroExpander {
266271 name : def. ident ,
267272 imported_from : def. imported_from ,
@@ -288,6 +293,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
288293 // after parsing/expansion. we can report every error in every macro this way.
289294}
290295
296+ /// Check that the lhs contains no repetition which could match an empty token
297+ /// tree, because then the matcher would hang indefinitely.
298+ fn check_lhs_no_empty_seq ( sess : & ParseSess , tts : & [ TokenTree ] ) -> bool {
299+ for tt in tts {
300+ match * tt {
301+ TokenTree :: Token ( _, _) => ( ) ,
302+ TokenTree :: Delimited ( _, ref del) => if !check_lhs_no_empty_seq ( sess, & del. tts ) {
303+ return false ;
304+ } ,
305+ TokenTree :: Sequence ( span, ref seq) => {
306+ if seq. separator . is_none ( ) {
307+ if seq. tts . iter ( ) . all ( |seq_tt| {
308+ match * seq_tt {
309+ TokenTree :: Sequence ( _, ref sub_seq) =>
310+ sub_seq. op == tokenstream:: KleeneOp :: ZeroOrMore ,
311+ _ => false ,
312+ }
313+ } ) {
314+ sess. span_diagnostic . span_err ( span, "repetition matches empty token tree" ) ;
315+ return false ;
316+ }
317+ }
318+ if !check_lhs_no_empty_seq ( sess, & seq. tts ) {
319+ return false ;
320+ }
321+ }
322+ }
323+ }
324+
325+ true
326+ }
327+
291328fn check_rhs ( sess : & ParseSess , rhs : & TokenTree ) -> bool {
292329 match * rhs {
293330 TokenTree :: Delimited ( ..) => return true ,
0 commit comments