@@ -243,7 +243,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
243
243
( * * tt) . clone ( )
244
244
}
245
245
_ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
246
- } ) . collect ( )
246
+ } ) . collect :: < Vec < TokenTree > > ( )
247
247
}
248
248
_ => sess. span_diagnostic . span_bug ( def. span , "wrong-structured lhs" )
249
249
} ;
@@ -262,6 +262,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
262
262
valid &= check_rhs ( sess, rhs) ;
263
263
}
264
264
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
+
265
270
let exp: Box < _ > = Box :: new ( MacroRulesMacroExpander {
266
271
name : def. ident ,
267
272
imported_from : def. imported_from ,
@@ -288,6 +293,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
288
293
// after parsing/expansion. we can report every error in every macro this way.
289
294
}
290
295
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
+
291
328
fn check_rhs ( sess : & ParseSess , rhs : & TokenTree ) -> bool {
292
329
match * rhs {
293
330
TokenTree :: Delimited ( ..) => return true ,
0 commit comments