about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-06-08 07:05:47 +0800
committerGitHub <noreply@github.com>2018-06-08 07:05:47 +0800
commite46ef1bb86f9f206da06e9d5b313f0ca31809832 (patch)
tree54c644daab720e9e3f2b45aaf8e1969c4c2aae8c /src/libsyntax/ext
parentc843607bcc282a14cd1e17342eaa17ff0223ccfa (diff)
parent1df781712297270c74d175552e420ae055a7f193 (diff)
downloadrust-e46ef1bb86f9f206da06e9d5b313f0ca31809832.tar.gz
rust-e46ef1bb86f9f206da06e9d5b313f0ca31809832.zip
Rollup merge of #51417 - pietroalbini:revert-49719, r=nikomatsakis
Revert #49719

This also needs to be backported into beta.

Fixes #51416.
r? @nikomatsakis
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/tt/quoted.rs89
1 files changed, 67 insertions, 22 deletions
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index 77c6afa1c64..01b971976a7 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -386,26 +386,72 @@ where
 {
     // We basically look at two token trees here, denoted as #1 and #2 below
     let span = match parse_kleene_op(input, span) {
-        // #1 is any KleeneOp (`?`)
-        Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
-            if !features.macro_at_most_once_rep
-                && !attr::contains_name(attrs, "allow_internal_unstable")
-            {
-                let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
-                emit_feature_err(
-                    sess,
-                    "macro_at_most_once_rep",
-                    span,
-                    GateIssue::Language,
-                    explain,
-                );
+        // #1 is a `+` or `*` KleeneOp
+        //
+        // `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look
+        // ahead one more token to be sure.
+        Ok(Ok(op)) if op != KleeneOp::ZeroOrOne => return (None, op),
+
+        // #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could
+        // be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to
+        // find out which.
+        Ok(Ok(op)) => {
+            assert_eq!(op, KleeneOp::ZeroOrOne);
+
+            // Lookahead at #2. If it is a KleenOp, then #1 is a separator.
+            let is_1_sep = if let Some(&tokenstream::TokenTree::Token(_, ref tok2)) = input.peek() {
+                kleene_op(tok2).is_some()
+            } else {
+                false
+            };
+
+            if is_1_sep {
+                // #1 is a separator and #2 should be a KleepeOp::*
+                // (N.B. We need to advance the input iterator.)
+                match parse_kleene_op(input, span) {
+                    // #2 is a KleeneOp (this is the only valid option) :)
+                    Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
+                        if !features.macro_at_most_once_rep
+                            && !attr::contains_name(attrs, "allow_internal_unstable")
+                        {
+                            let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
+                            emit_feature_err(
+                                sess,
+                                "macro_at_most_once_rep",
+                                span,
+                                GateIssue::Language,
+                                explain,
+                            );
+                        }
+                        return (Some(token::Question), op);
+                    }
+                    Ok(Ok(op)) => return (Some(token::Question), op),
+
+                    // #2 is a random token (this is an error) :(
+                    Ok(Err((_, span))) => span,
+
+                    // #2 is not even a token at all :(
+                    Err(span) => span,
+                }
+            } else {
+                if !features.macro_at_most_once_rep
+                    && !attr::contains_name(attrs, "allow_internal_unstable")
+                {
+                    let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
+                    emit_feature_err(
+                        sess,
+                        "macro_at_most_once_rep",
+                        span,
+                        GateIssue::Language,
+                        explain,
+                    );
+                }
+
+                // #2 is a random tree and #1 is KleeneOp::ZeroOrOne
+                return (None, op);
             }
-            return (None, op);
         }
 
-        // #1 is any KleeneOp (`+`, `*`)
-        Ok(Ok(op)) => return (None, op),
-
         // #1 is a separator followed by #2, a KleeneOp
         Ok(Err((tok, span))) => match parse_kleene_op(input, span) {
             // #2 is a KleeneOp :D
@@ -421,11 +467,8 @@ where
                         GateIssue::Language,
                         explain,
                     );
-                } else {
-                    sess.span_diagnostic
-                        .span_err(span, "`?` macro repetition does not allow a separator");
                 }
-                return (None, op);
+                return (Some(tok), op);
             }
             Ok(Ok(op)) => return (Some(tok), op),
 
@@ -440,7 +483,9 @@ where
         Err(span) => span,
     };
 
-    if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") {
+    if !features.macro_at_most_once_rep
+        && !attr::contains_name(attrs, "allow_internal_unstable")
+    {
         sess.span_diagnostic
             .span_err(span, "expected one of: `*`, `+`, or `?`");
     } else {