Rollup merge of #36721 - TimNN:infinite-emptiness, r=nrc
reject macros with empty repetitions Fixes #5067 by checking the lhs of `macro_rules!` for repetitions which could match an empty token tree.
This commit is contained in:
commit
02cc578676
@ -243,7 +243,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")
|
||||
};
|
||||
@ -262,6 +262,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,
|
||||
@ -288,6 +293,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,
|
||||
|
62
src/test/compile-fail/issue-5067.rs
Normal file
62
src/test/compile-fail/issue-5067.rs
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
macro_rules! foo {
|
||||
( $()* ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
( $()+ ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
|
||||
( $(),* ) => {}; // PASS
|
||||
( $(),+ ) => {}; // PASS
|
||||
|
||||
( [$()*] ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
( [$()+] ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
|
||||
( [$(),*] ) => {}; // PASS
|
||||
( [$(),+] ) => {}; // PASS
|
||||
|
||||
( $($()* $(),* $(a)* $(a),* )* ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
( $($()* $(),* $(a)* $(a),* )+ ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
|
||||
( $(a $(),* $(a)* $(a),* )* ) => {}; // PASS
|
||||
( $($(a)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS
|
||||
|
||||
( $(a $()+)* ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
( $(a $()*)+ ) => {};
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
}
|
||||
|
||||
|
||||
// --- Original Issue --- //
|
||||
|
||||
macro_rules! make_vec {
|
||||
(a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]);
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = make_vec!(a 1, a 2, a 3);
|
||||
}
|
||||
|
||||
|
||||
// --- Minified Issue --- //
|
||||
|
||||
macro_rules! m {
|
||||
( $()* ) => {}
|
||||
//~^ ERROR repetition matches empty token tree
|
||||
}
|
||||
|
||||
m!();
|
Loading…
Reference in New Issue
Block a user