Rollup merge of #57610 - mark-i-m:nested-matchers, r=petrochenkov

Fix nested `?` matchers

fix #57597

I'm not 100% if this works yet...

cc @alercah

When  this is ready (but perhaps not yet):
This commit is contained in:
Mazdak Farrokhzad 2019-01-19 09:03:28 +01:00 committed by GitHub
commit fd779d3f76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 253 additions and 24 deletions

View file

@ -435,7 +435,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
match *seq_tt { match *seq_tt {
TokenTree::MetaVarDecl(_, _, id) => id.name == "vis", TokenTree::MetaVarDecl(_, _, id) => id.name == "vis",
TokenTree::Sequence(_, ref sub_seq) => TokenTree::Sequence(_, ref sub_seq) =>
sub_seq.op == quoted::KleeneOp::ZeroOrMore, sub_seq.op == quoted::KleeneOp::ZeroOrMore
|| sub_seq.op == quoted::KleeneOp::ZeroOrOne,
_ => false, _ => false,
} }
}) { }) {
@ -543,7 +544,10 @@ impl FirstSets {
} }
// Reverse scan: Sequence comes before `first`. // Reverse scan: Sequence comes before `first`.
if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore { if subfirst.maybe_empty
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
{
// If sequence is potentially empty, then // If sequence is potentially empty, then
// union them (preserving first emptiness). // union them (preserving first emptiness).
first.add_all(&TokenSet { maybe_empty: true, ..subfirst }); first.add_all(&TokenSet { maybe_empty: true, ..subfirst });
@ -591,8 +595,10 @@ impl FirstSets {
assert!(first.maybe_empty); assert!(first.maybe_empty);
first.add_all(subfirst); first.add_all(subfirst);
if subfirst.maybe_empty || if subfirst.maybe_empty
seq_rep.op == quoted::KleeneOp::ZeroOrMore { || seq_rep.op == quoted::KleeneOp::ZeroOrMore
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
{
// continue scanning for more first // continue scanning for more first
// tokens, but also make sure we // tokens, but also make sure we
// restore empty-tracking state // restore empty-tracking state

View file

@ -1,37 +1,59 @@
#![allow(unused_macros)] #![allow(unused_macros)]
// Tests that repetition matchers cannot match the empty token tree (since that would be
// ambiguous).
// edition:2018
macro_rules! foo { macro_rules! foo {
( $()* ) => {}; ( $()* ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( $()+ ) => {}; ( $()+ ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( $()? ) => {};
//~^ ERROR repetition matches empty token tree
( $(),* ) => {}; // PASS ( $(),* ) => {}; // PASS
( $(),+ ) => {}; // PASS ( $(),+ ) => {}; // PASS
// `?` cannot have a separator...
( [$()*] ) => {}; ( [$()*] ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( [$()+] ) => {}; ( [$()+] ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( [$()?] ) => {};
//~^ ERROR repetition matches empty token tree
( [$(),*] ) => {}; // PASS ( [$(),*] ) => {}; // PASS
( [$(),+] ) => {}; // PASS ( [$(),+] ) => {}; // PASS
// `?` cannot have a separator...
( $($()* $(),* $(a)* $(a),* )* ) => {}; ( $($()* $(),* $(a)* $(a),* )* ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( $($()* $(),* $(a)* $(a),* )+ ) => {}; ( $($()* $(),* $(a)* $(a),* )+ ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( $($()* $(),* $(a)* $(a),* )? ) => {};
//~^ ERROR repetition matches empty token tree
( $($()? $(),* $(a)? $(a),* )* ) => {};
//~^ ERROR repetition matches empty token tree
( $($()? $(),* $(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)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS ( $($(a)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS
( $($(a)+ $(),* $(a)* $(a),* )? ) => {}; // PASS
( $(a $(),* $(a)? $(a),* )* ) => {}; // PASS
( $($(a)+ $(),* $(a)? $(a),* )+ ) => {}; // PASS
( $($(a)+ $(),* $(a)? $(a),* )? ) => {}; // PASS
( $(a $()+)* ) => {}; ( $(a $()+)* ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( $(a $()*)+ ) => {}; ( $(a $()*)+ ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
( $(a $()+)? ) => {};
//~^ ERROR repetition matches empty token tree
( $(a $()?)+ ) => {};
//~^ ERROR repetition matches empty token tree
} }
// --- Original Issue --- // // --- Original Issue --- //
macro_rules! make_vec { macro_rules! make_vec {
@ -43,11 +65,10 @@ fn main() {
let _ = make_vec![a 1, a 2, a 3]; let _ = make_vec![a 1, a 2, a 3];
} }
// --- Minified Issue --- // // --- Minified Issue --- //
macro_rules! m { macro_rules! m {
( $()* ) => {} ( $()* ) => {};
//~^ ERROR repetition matches empty token tree //~^ ERROR repetition matches empty token tree
} }

View file

@ -1,62 +1,110 @@
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:4:8 --> $DIR/issue-5067.rs:9:8
| |
LL | ( $()* ) => {}; LL | ( $()* ) => {};
| ^^ | ^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:6:8 --> $DIR/issue-5067.rs:11:8
| |
LL | ( $()+ ) => {}; LL | ( $()+ ) => {};
| ^^ | ^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:12:9 --> $DIR/issue-5067.rs:13:8
|
LL | ( $()? ) => {};
| ^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:18:9
| |
LL | ( [$()*] ) => {}; LL | ( [$()*] ) => {};
| ^^ | ^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:14:9 --> $DIR/issue-5067.rs:20:9
| |
LL | ( [$()+] ) => {}; LL | ( [$()+] ) => {};
| ^^ | ^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:20:8 --> $DIR/issue-5067.rs:22:9
|
LL | ( [$()?] ) => {};
| ^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:27:8
| |
LL | ( $($()* $(),* $(a)* $(a),* )* ) => {}; LL | ( $($()* $(),* $(a)* $(a),* )* ) => {};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:22:8 --> $DIR/issue-5067.rs:29:8
| |
LL | ( $($()* $(),* $(a)* $(a),* )+ ) => {}; LL | ( $($()* $(),* $(a)* $(a),* )+ ) => {};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:28:12 --> $DIR/issue-5067.rs:31:8
|
LL | ( $($()* $(),* $(a)* $(a),* )? ) => {};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:33:8
|
LL | ( $($()? $(),* $(a)? $(a),* )* ) => {};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:35:8
|
LL | ( $($()? $(),* $(a)? $(a),* )+ ) => {};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:37:8
|
LL | ( $($()? $(),* $(a)? $(a),* )? ) => {};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:47:12
| |
LL | ( $(a $()+)* ) => {}; LL | ( $(a $()+)* ) => {};
| ^^ | ^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:30:12 --> $DIR/issue-5067.rs:49:12
| |
LL | ( $(a $()*)+ ) => {}; LL | ( $(a $()*)+ ) => {};
| ^^ | ^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:38:18 --> $DIR/issue-5067.rs:51:12
|
LL | ( $(a $()+)? ) => {};
| ^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:53:12
|
LL | ( $(a $()?)+ ) => {};
| ^^
error: repetition matches empty token tree
--> $DIR/issue-5067.rs:60:18
| |
LL | (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]); LL | (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]);
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree error: repetition matches empty token tree
--> $DIR/issue-5067.rs:50:8 --> $DIR/issue-5067.rs:71:8
| |
LL | ( $()* ) => {} LL | ( $()* ) => {};
| ^^ | ^^
error: aborting due to 10 previous errors error: aborting due to 18 previous errors

View file

@ -0,0 +1,80 @@
// Regression test for #57597.
//
// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
// edition:2018
macro_rules! foo1 {
($($($i:ident)?)+) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo2 {
($($($i:ident)?)*) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo3 {
($($($i:ident)?)?) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo4 {
($($($($i:ident)?)?)?) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo5 {
($($($($i:ident)*)?)?) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo6 {
($($($($i:ident)?)*)?) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo7 {
($($($($i:ident)?)?)*) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo8 {
($($($($i:ident)*)*)?) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo9 {
($($($($i:ident)?)*)*) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo10 {
($($($($i:ident)?)*)+) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo11 {
($($($($i:ident)+)?)*) => {};
//~^ ERROR repetition matches empty token tree
}
macro_rules! foo12 {
($($($($i:ident)+)*)?) => {};
//~^ ERROR repetition matches empty token tree
}
fn main() {
foo1!();
foo2!();
foo3!();
foo4!();
foo5!();
foo6!();
foo7!();
foo8!();
foo9!();
foo10!();
foo11!();
foo12!();
}

View file

@ -0,0 +1,74 @@
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:8:7
|
LL | ($($($i:ident)?)+) => {};
| ^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:13:7
|
LL | ($($($i:ident)?)*) => {};
| ^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:18:7
|
LL | ($($($i:ident)?)?) => {};
| ^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:23:7
|
LL | ($($($($i:ident)?)?)?) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:28:7
|
LL | ($($($($i:ident)*)?)?) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:33:7
|
LL | ($($($($i:ident)?)*)?) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:38:7
|
LL | ($($($($i:ident)?)?)*) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:43:7
|
LL | ($($($($i:ident)*)*)?) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:48:7
|
LL | ($($($($i:ident)?)*)*) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:53:7
|
LL | ($($($($i:ident)?)*)+) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:58:7
|
LL | ($($($($i:ident)+)?)*) => {};
| ^^^^^^^^^^^^^^^^^^
error: repetition matches empty token tree
--> $DIR/issue-57597.rs:63:7
|
LL | ($($($($i:ident)+)*)?) => {};
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors