about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJulien Cretin <cretin@google.com>2019-05-29 20:29:51 +0200
committerJulien Cretin <cretin@google.com>2019-07-19 19:59:11 +0200
commit82abc0db816e7441a0d89a3eaa51f439a03f4506 (patch)
tree9674a3548e72a1b15ef4a05022ebd2dd6cfa36ad
parent527dce7137f7a3c7bf47d9a503abf25f88ea22de (diff)
Remember the span of the Kleene operator in macros
This is needed for having complete error messages where reporting macro variable
errors. Here is what they would look like:

error: meta-variable repeats with different kleene operator
  --> $DIR/issue-61053-different-kleene.rs:3:57
   |
LL |     ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* };
   |                                 - expected repetition   ^^   - conflicting repetition
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs6
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs16
-rw-r--r--src/libsyntax/ext/tt/quoted.rs30
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs2
4 files changed, 33 insertions, 21 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index fc8aa4793bc..ae1979540ff 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -557,8 +557,8 @@ fn inner_parse_loop<'root, 'tt>(
                     // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will
                     // result in a "no rules expected token" error by virtue of this matcher not
                     // working.
-                    if seq.op == quoted::KleeneOp::ZeroOrMore
-                        || seq.op == quoted::KleeneOp::ZeroOrOne
+                    if seq.kleene.op == quoted::KleeneOp::ZeroOrMore
+                        || seq.kleene.op == quoted::KleeneOp::ZeroOrOne
                     {
                         let mut new_item = item.clone();
                         new_item.match_cur += seq.num_captures;
@@ -573,7 +573,7 @@ fn inner_parse_loop<'root, 'tt>(
                     cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos {
                         stack: smallvec![],
                         sep: seq.separator.clone(),
-                        seq_op: Some(seq.op),
+                        seq_op: Some(seq.kleene.op),
                         idx: 0,
                         matches,
                         match_lo: item.match_cur,
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 5c6438a7ef5..54f901d095b 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -273,7 +273,7 @@ pub fn compile(
                     if body.legacy { token::Semi } else { token::Comma },
                     def.span,
                 )),
-                op: quoted::KleeneOp::OneOrMore,
+                kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span),
                 num_captures: 2,
             }),
         ),
@@ -283,7 +283,7 @@ pub fn compile(
             Lrc::new(quoted::SequenceRepetition {
                 tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
                 separator: None,
-                op: quoted::KleeneOp::ZeroOrMore,
+                kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
                 num_captures: 0,
             }),
         ),
@@ -477,8 +477,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
                     && seq.tts.iter().all(|seq_tt| match *seq_tt {
                         TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
                         TokenTree::Sequence(_, ref sub_seq) => {
-                            sub_seq.op == quoted::KleeneOp::ZeroOrMore
-                                || sub_seq.op == quoted::KleeneOp::ZeroOrOne
+                            sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore
+                                || sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne
                         }
                         _ => false,
                     })
@@ -628,8 +628,8 @@ impl FirstSets {
 
                         // Reverse scan: Sequence comes before `first`.
                         if subfirst.maybe_empty
-                            || seq_rep.op == quoted::KleeneOp::ZeroOrMore
-                            || seq_rep.op == quoted::KleeneOp::ZeroOrOne
+                            || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
+                            || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
                         {
                             // If sequence is potentially empty, then
                             // union them (preserving first emptiness).
@@ -677,8 +677,8 @@ impl FirstSets {
                             assert!(first.maybe_empty);
                             first.add_all(subfirst);
                             if subfirst.maybe_empty
-                                || seq_rep.op == quoted::KleeneOp::ZeroOrMore
-                                || seq_rep.op == quoted::KleeneOp::ZeroOrOne
+                                || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
+                                || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
                             {
                                 // continue scanning for more first
                                 // tokens, but also make sure we
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index ccf9db842ab..eff6b9dd429 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -50,11 +50,23 @@ pub struct SequenceRepetition {
     /// The optional separator
     pub separator: Option<Token>,
     /// Whether the sequence can be repeated zero (*), or one or more times (+)
-    pub op: KleeneOp,
+    pub kleene: KleeneToken,
     /// The number of `Match`s that appear in the sequence (and subsequences)
     pub num_captures: usize,
 }
 
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+pub struct KleeneToken {
+    pub span: Span,
+    pub op: KleeneOp,
+}
+
+impl KleeneToken {
+    pub fn new(op: KleeneOp, span: Span) -> KleeneToken {
+        KleeneToken { span, op }
+    }
+}
+
 /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
 /// for token sequences.
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
@@ -273,7 +285,7 @@ fn parse_tree(
                     macro_node_id,
                 );
                 // Get the Kleene operator and optional separator
-                let (separator, op) = parse_sep_and_kleene_op(trees, span.entire(), sess);
+                let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess);
                 // Count the number of captured "names" (i.e., named metavars)
                 let name_captures = macro_parser::count_names(&sequence);
                 TokenTree::Sequence(
@@ -281,7 +293,7 @@ fn parse_tree(
                     Lrc::new(SequenceRepetition {
                         tts: sequence,
                         separator,
-                        op,
+                        kleene,
                         num_captures: name_captures,
                     }),
                 )
@@ -379,16 +391,16 @@ fn parse_sep_and_kleene_op(
     input: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>,
     span: Span,
     sess: &ParseSess,
-) -> (Option<Token>, KleeneOp) {
+) -> (Option<Token>, KleeneToken) {
     // We basically look at two token trees here, denoted as #1 and #2 below
     let span = match parse_kleene_op(input, span) {
         // #1 is a `?`, `+`, or `*` KleeneOp
-        Ok(Ok((op, _))) => return (None, op),
+        Ok(Ok((op, span))) => return (None, KleeneToken::new(op, span)),
 
         // #1 is a separator followed by #2, a KleeneOp
         Ok(Err(token)) => match parse_kleene_op(input, token.span) {
             // #2 is the `?` Kleene op, which does not take a separator (error)
-            Ok(Ok((KleeneOp::ZeroOrOne, _))) => {
+            Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
                 // Error!
                 sess.span_diagnostic.span_err(
                     token.span,
@@ -396,11 +408,11 @@ fn parse_sep_and_kleene_op(
                 );
 
                 // Return a dummy
-                return (None, KleeneOp::ZeroOrMore);
+                return (None, KleeneToken::new(KleeneOp::ZeroOrMore, span));
             }
 
             // #2 is a KleeneOp :D
-            Ok(Ok((op, _))) => return (Some(token), op),
+            Ok(Ok((op, span))) => return (Some(token), KleeneToken::new(op, span)),
 
             // #2 is a random token or not a token at all :(
             Ok(Err(Token { span, .. })) | Err(span) => span,
@@ -414,5 +426,5 @@ fn parse_sep_and_kleene_op(
     sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
 
     // Return a dummy
-    (None, KleeneOp::ZeroOrMore)
+    (None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
 }
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index e04fd2ddc05..93a2f506901 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -183,7 +183,7 @@ pub fn transcribe(
 
                         // Is the repetition empty?
                         if len == 0 {
-                            if seq.op == quoted::KleeneOp::OneOrMore {
+                            if seq.kleene.op == quoted::KleeneOp::OneOrMore {
                                 // FIXME: this really ought to be caught at macro definition
                                 // time... It happens when the Kleene operator in the matcher and
                                 // the body for the same meta-variable do not match.