Skip to content

Commit efce22c

Browse files
committed
Revert "Auto merge of #49719 - mark-i-m:no_sep, r=petrochenkov"
This reverts commit d6ba1b9, reversing changes made to 8de5353.
1 parent eb01d0f commit efce22c

File tree

4 files changed

+156
-72
lines changed

4 files changed

+156
-72
lines changed

src/libsyntax/ext/tt/quoted.rs

+67-22
Original file line numberDiff line numberDiff line change
@@ -386,26 +386,72 @@ where
386386
{
387387
// We basically look at two token trees here, denoted as #1 and #2 below
388388
let span = match parse_kleene_op(input, span) {
389-
// #1 is any KleeneOp (`?`)
390-
Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
391-
if !features.macro_at_most_once_rep
392-
&& !attr::contains_name(attrs, "allow_internal_unstable")
393-
{
394-
let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
395-
emit_feature_err(
396-
sess,
397-
"macro_at_most_once_rep",
398-
span,
399-
GateIssue::Language,
400-
explain,
401-
);
389+
// #1 is a `+` or `*` KleeneOp
390+
//
391+
// `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look
392+
// ahead one more token to be sure.
393+
Ok(Ok(op)) if op != KleeneOp::ZeroOrOne => return (None, op),
394+
395+
// #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could
396+
// be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to
397+
// find out which.
398+
Ok(Ok(op)) => {
399+
assert_eq!(op, KleeneOp::ZeroOrOne);
400+
401+
// Lookahead at #2. If it is a KleenOp, then #1 is a separator.
402+
let is_1_sep = if let Some(&tokenstream::TokenTree::Token(_, ref tok2)) = input.peek() {
403+
kleene_op(tok2).is_some()
404+
} else {
405+
false
406+
};
407+
408+
if is_1_sep {
409+
// #1 is a separator and #2 should be a KleepeOp::*
410+
// (N.B. We need to advance the input iterator.)
411+
match parse_kleene_op(input, span) {
412+
// #2 is a KleeneOp (this is the only valid option) :)
413+
Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
414+
if !features.macro_at_most_once_rep
415+
&& !attr::contains_name(attrs, "allow_internal_unstable")
416+
{
417+
let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
418+
emit_feature_err(
419+
sess,
420+
"macro_at_most_once_rep",
421+
span,
422+
GateIssue::Language,
423+
explain,
424+
);
425+
}
426+
return (Some(token::Question), op);
427+
}
428+
Ok(Ok(op)) => return (Some(token::Question), op),
429+
430+
// #2 is a random token (this is an error) :(
431+
Ok(Err((_, span))) => span,
432+
433+
// #2 is not even a token at all :(
434+
Err(span) => span,
435+
}
436+
} else {
437+
if !features.macro_at_most_once_rep
438+
&& !attr::contains_name(attrs, "allow_internal_unstable")
439+
{
440+
let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
441+
emit_feature_err(
442+
sess,
443+
"macro_at_most_once_rep",
444+
span,
445+
GateIssue::Language,
446+
explain,
447+
);
448+
}
449+
450+
// #2 is a random tree and #1 is KleeneOp::ZeroOrOne
451+
return (None, op);
402452
}
403-
return (None, op);
404453
}
405454

406-
// #1 is any KleeneOp (`+`, `*`)
407-
Ok(Ok(op)) => return (None, op),
408-
409455
// #1 is a separator followed by #2, a KleeneOp
410456
Ok(Err((tok, span))) => match parse_kleene_op(input, span) {
411457
// #2 is a KleeneOp :D
@@ -421,11 +467,8 @@ where
421467
GateIssue::Language,
422468
explain,
423469
);
424-
} else {
425-
sess.span_diagnostic
426-
.span_err(span, "`?` macro repetition does not allow a separator");
427470
}
428-
return (None, op);
471+
return (Some(tok), op);
429472
}
430473
Ok(Ok(op)) => return (Some(tok), op),
431474

@@ -440,7 +483,9 @@ where
440483
Err(span) => span,
441484
};
442485

443-
if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") {
486+
if !features.macro_at_most_once_rep
487+
&& !attr::contains_name(attrs, "allow_internal_unstable")
488+
{
444489
sess.span_diagnostic
445490
.span_err(span, "expected one of: `*`, `+`, or `?`");
446491
} else {

src/test/run-pass/macro-at-most-once-rep.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,25 @@ macro_rules! foo {
3232
} }
3333
}
3434

35+
macro_rules! baz {
36+
($($a:ident),? ; $num:expr) => { { // comma separator is meaningless for `?`
37+
let mut x = 0;
38+
39+
$(
40+
x += $a;
41+
)?
42+
43+
assert_eq!(x, $num);
44+
} }
45+
}
46+
3547
macro_rules! barplus {
3648
($($a:ident)?+ ; $num:expr) => { {
3749
let mut x = 0;
3850

3951
$(
4052
x += $a;
41-
)?
53+
)+
4254

4355
assert_eq!(x, $num);
4456
} }
@@ -50,7 +62,7 @@ macro_rules! barstar {
5062

5163
$(
5264
x += $a;
53-
)?
65+
)*
5466

5567
assert_eq!(x, $num);
5668
} }
@@ -62,10 +74,15 @@ pub fn main() {
6274
// accept 0 or 1 repetitions
6375
foo!( ; 0);
6476
foo!(a ; 1);
77+
baz!( ; 0);
78+
baz!(a ; 1);
6579

6680
// Make sure using ? as a separator works as before
67-
barplus!(+ ; 0);
68-
barplus!(a + ; 1);
69-
barstar!(* ; 0);
70-
barstar!(a * ; 1);
81+
barplus!(a ; 1);
82+
barplus!(a?a ; 2);
83+
barplus!(a?a?a ; 3);
84+
barstar!( ; 0);
85+
barstar!(a ; 1);
86+
barstar!(a?a ; 2);
87+
barstar!(a?a?a ; 3);
7188
}

src/test/ui/macros/macro-at-most-once-rep-ambig.rs

+19-15
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,30 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// Tests the behavior of various Kleene operators in macros with respect to `?` terminals. In
12-
// particular, `?` in the position of a separator and of a Kleene operator is tested.
11+
// The logic for parsing Kleene operators in macros has a special case to disambiguate `?`.
12+
// Specifically, `$(pat)?` is the ZeroOrOne operator whereas `$(pat)?+` or `$(pat)?*` are the
13+
// ZeroOrMore and OneOrMore operators using `?` as a separator. These tests are intended to
14+
// exercise that logic in the macro parser.
15+
//
16+
// Moreover, we also throw in some tests for using a separator with `?`, which is meaningless but
17+
// included for consistency with `+` and `*`.
18+
//
19+
// This test focuses on error cases.
1320

1421
#![feature(macro_at_most_once_rep)]
1522

16-
// should match `` and `a`
1723
macro_rules! foo {
1824
($(a)?) => {}
1925
}
2026

2127
macro_rules! baz {
22-
($(a),?) => {} //~ ERROR `?` macro repetition does not allow a separator
28+
($(a),?) => {} // comma separator is meaningless for `?`
2329
}
2430

25-
// should match `+` and `a+`
2631
macro_rules! barplus {
2732
($(a)?+) => {}
2833
}
2934

30-
// should match `*` and `a*`
3135
macro_rules! barstar {
3236
($(a)?*) => {}
3337
}
@@ -36,14 +40,14 @@ pub fn main() {
3640
foo!(a?a?a); //~ ERROR no rules expected the token `?`
3741
foo!(a?a); //~ ERROR no rules expected the token `?`
3842
foo!(a?); //~ ERROR no rules expected the token `?`
43+
baz!(a?a?a); //~ ERROR no rules expected the token `?`
44+
baz!(a?a); //~ ERROR no rules expected the token `?`
45+
baz!(a?); //~ ERROR no rules expected the token `?`
46+
baz!(a,); //~ ERROR unexpected end of macro invocation
47+
baz!(a?a?a,); //~ ERROR no rules expected the token `?`
48+
baz!(a?a,); //~ ERROR no rules expected the token `?`
49+
baz!(a?,); //~ ERROR no rules expected the token `?`
3950
barplus!(); //~ ERROR unexpected end of macro invocation
40-
barstar!(); //~ ERROR unexpected end of macro invocation
41-
barplus!(a?); //~ ERROR no rules expected the token `?`
42-
barplus!(a); //~ ERROR unexpected end of macro invocation
43-
barstar!(a?); //~ ERROR no rules expected the token `?`
44-
barstar!(a); //~ ERROR unexpected end of macro invocation
45-
barplus!(+); // ok
46-
barstar!(*); // ok
47-
barplus!(a+); // ok
48-
barstar!(a*); // ok
51+
barplus!(a?); //~ ERROR unexpected end of macro invocation
52+
barstar!(a?); //~ ERROR unexpected end of macro invocation
4953
}
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,80 @@
1-
error: `?` macro repetition does not allow a separator
2-
--> $DIR/macro-at-most-once-rep-ambig.rs:22:10
3-
|
4-
LL | ($(a),?) => {} //~ ERROR `?` macro repetition does not allow a separator
5-
| ^
6-
71
error: no rules expected the token `?`
8-
--> $DIR/macro-at-most-once-rep-ambig.rs:36:11
2+
--> $DIR/macro-at-most-once-rep-ambig.rs:40:11
93
|
104
LL | foo!(a?a?a); //~ ERROR no rules expected the token `?`
115
| ^
126

137
error: no rules expected the token `?`
14-
--> $DIR/macro-at-most-once-rep-ambig.rs:37:11
8+
--> $DIR/macro-at-most-once-rep-ambig.rs:41:11
159
|
1610
LL | foo!(a?a); //~ ERROR no rules expected the token `?`
1711
| ^
1812

1913
error: no rules expected the token `?`
20-
--> $DIR/macro-at-most-once-rep-ambig.rs:38:11
14+
--> $DIR/macro-at-most-once-rep-ambig.rs:42:11
2115
|
2216
LL | foo!(a?); //~ ERROR no rules expected the token `?`
2317
| ^
2418

25-
error: unexpected end of macro invocation
26-
--> $DIR/macro-at-most-once-rep-ambig.rs:39:5
19+
error: no rules expected the token `?`
20+
--> $DIR/macro-at-most-once-rep-ambig.rs:43:11
2721
|
28-
LL | barplus!(); //~ ERROR unexpected end of macro invocation
29-
| ^^^^^^^^^^^
22+
LL | baz!(a?a?a); //~ ERROR no rules expected the token `?`
23+
| ^
3024

31-
error: unexpected end of macro invocation
32-
--> $DIR/macro-at-most-once-rep-ambig.rs:40:5
25+
error: no rules expected the token `?`
26+
--> $DIR/macro-at-most-once-rep-ambig.rs:44:11
3327
|
34-
LL | barstar!(); //~ ERROR unexpected end of macro invocation
35-
| ^^^^^^^^^^^
28+
LL | baz!(a?a); //~ ERROR no rules expected the token `?`
29+
| ^
3630

3731
error: no rules expected the token `?`
38-
--> $DIR/macro-at-most-once-rep-ambig.rs:41:15
32+
--> $DIR/macro-at-most-once-rep-ambig.rs:45:11
3933
|
40-
LL | barplus!(a?); //~ ERROR no rules expected the token `?`
41-
| ^
34+
LL | baz!(a?); //~ ERROR no rules expected the token `?`
35+
| ^
4236

4337
error: unexpected end of macro invocation
44-
--> $DIR/macro-at-most-once-rep-ambig.rs:42:14
38+
--> $DIR/macro-at-most-once-rep-ambig.rs:46:11
39+
|
40+
LL | baz!(a,); //~ ERROR unexpected end of macro invocation
41+
| ^
42+
43+
error: no rules expected the token `?`
44+
--> $DIR/macro-at-most-once-rep-ambig.rs:47:11
45+
|
46+
LL | baz!(a?a?a,); //~ ERROR no rules expected the token `?`
47+
| ^
48+
49+
error: no rules expected the token `?`
50+
--> $DIR/macro-at-most-once-rep-ambig.rs:48:11
4551
|
46-
LL | barplus!(a); //~ ERROR unexpected end of macro invocation
47-
| ^
52+
LL | baz!(a?a,); //~ ERROR no rules expected the token `?`
53+
| ^
4854

4955
error: no rules expected the token `?`
50-
--> $DIR/macro-at-most-once-rep-ambig.rs:43:15
56+
--> $DIR/macro-at-most-once-rep-ambig.rs:49:11
57+
|
58+
LL | baz!(a?,); //~ ERROR no rules expected the token `?`
59+
| ^
60+
61+
error: unexpected end of macro invocation
62+
--> $DIR/macro-at-most-once-rep-ambig.rs:50:5
63+
|
64+
LL | barplus!(); //~ ERROR unexpected end of macro invocation
65+
| ^^^^^^^^^^^
66+
67+
error: unexpected end of macro invocation
68+
--> $DIR/macro-at-most-once-rep-ambig.rs:51:15
5169
|
52-
LL | barstar!(a?); //~ ERROR no rules expected the token `?`
70+
LL | barplus!(a?); //~ ERROR unexpected end of macro invocation
5371
| ^
5472

5573
error: unexpected end of macro invocation
56-
--> $DIR/macro-at-most-once-rep-ambig.rs:44:14
74+
--> $DIR/macro-at-most-once-rep-ambig.rs:52:15
5775
|
58-
LL | barstar!(a); //~ ERROR unexpected end of macro invocation
59-
| ^
76+
LL | barstar!(a?); //~ ERROR unexpected end of macro invocation
77+
| ^
6078

61-
error: aborting due to 10 previous errors
79+
error: aborting due to 13 previous errors
6280

0 commit comments

Comments
 (0)