diff options
| author | Tim Neumann <mail@timnn.me> | 2016-09-25 18:55:04 +0200 |
|---|---|---|
| committer | Tim Neumann <mail@timnn.me> | 2016-09-26 06:59:06 +0200 |
| commit | 51ea0504578c00b6754b666032c19366a197a480 (patch) | |
| tree | 6f6def132307adb4fa5616718b93b5c1354df444 /src/libsyntax | |
| parent | 95abee1a680f008fb97472294dd376a66e06d311 (diff) | |
| download | rust-51ea0504578c00b6754b666032c19366a197a480.tar.gz rust-51ea0504578c00b6754b666032c19366a197a480.zip | |
reject macros with empty repetitions
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 0eed3e5898c..cb92f61ebaa 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -332,7 +332,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { (**tt).clone() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") - }).collect() + }).collect::<Vec<TokenTree>>() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }; @@ -351,6 +351,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { valid &= check_rhs(sess, rhs); } + // don't abort iteration early, so that errors for multiple lhses can be reported + for lhs in &lhses { + valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()]) + } + let exp: Box<_> = Box::new(MacroRulesMacroExpander { name: def.ident, imported_from: def.imported_from, @@ -377,6 +382,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool { // after parsing/expansion. we can report every error in every macro this way. } +/// Check that the lhs contains no repetition which could match an empty token +/// tree, because then the matcher would hang indefinitely. +fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool { + for tt in tts { + match *tt { + TokenTree::Token(_, _) => (), + TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) { + return false; + }, + TokenTree::Sequence(span, ref seq) => { + if seq.separator.is_none() { + if seq.tts.iter().all(|seq_tt| { + match *seq_tt { + TokenTree::Sequence(_, ref sub_seq) => + sub_seq.op == tokenstream::KleeneOp::ZeroOrMore, + _ => false, + } + }) { + sess.span_diagnostic.span_err(span, "repetition matches empty token tree"); + return false; + } + } + if !check_lhs_no_empty_seq(sess, &seq.tts) { + return false; + } + } + } + } + + true +} + fn check_rhs(sess: &ParseSess, rhs: &TokenTree) -> bool { match *rhs { TokenTree::Delimited(..) => return true, |
