about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2016-10-19 08:00:01 +0300
committerGitHub <noreply@github.com>2016-10-19 08:00:01 +0300
commit094eaf025089218733305858fa262f826b6f11b8 (patch)
tree46370228599af762a75c9b05f8d66353d6be1139 /src/libsyntax
parent45683187ea6887fd5ceab631b4534ed79e7f8397 (diff)
parent95a9e2a724019c11c9b69a45e7953f8ba1225df9 (diff)
downloadrust-094eaf025089218733305858fa262f826b6f11b8.tar.gz
rust-094eaf025089218733305858fa262f826b6f11b8.zip
Rollup merge of #37208 - jseyfried:fix_partially_consumed_tokens_in_macros, r=nrc
macros: fix partially consumed tokens in macro matchers

Fixes #37175.

This PR also avoids re-transcribing the tokens consumed by a matcher (and cloning the `TtReader` once per matcher), which improves expansion performance of the test case from #34630 by ~8%.

r? @nrc
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs21
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs5
-rw-r--r--src/libsyntax/parse/lexer/mod.rs27
3 files changed, 38 insertions, 15 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 030cb303832..ef2e466a043 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -476,24 +476,21 @@ pub fn parse(sess: &ParseSess,
                 }
                 rdr.next_token();
             } else /* bb_eis.len() == 1 */ {
-                let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(rdr.clone()));
-
-                let mut ei = bb_eis.pop().unwrap();
-                match ei.top_elts.get_tt(ei.idx) {
-                    TokenTree::Token(span, MatchNt(_, ident)) => {
+                rdr.next_tok = {
+                    let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(&mut rdr));
+                    let mut ei = bb_eis.pop().unwrap();
+                    if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) {
                         let match_cur = ei.match_cur;
                         (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal(
                             parse_nt(&mut rust_parser, span, &ident.name.as_str()))));
                         ei.idx += 1;
                         ei.match_cur += 1;
+                    } else {
+                        unreachable!()
                     }
-                    _ => panic!()
-                }
-                cur_eis.push(ei);
-
-                for _ in 0..rust_parser.tokens_consumed {
-                    let _ = rdr.next_token();
-                }
+                    cur_eis.push(ei);
+                    Some(TokenAndSpan { tok: rust_parser.token, sp: rust_parser.span })
+                };
             }
         }
 
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 939425378de..205c709d6cb 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -48,6 +48,7 @@ pub struct TtReader<'a> {
     /* cached: */
     pub cur_tok: Token,
     pub cur_span: Span,
+    pub next_tok: Option<TokenAndSpan>,
     /// Transform doc comments. Only useful in macro invocations
     pub desugar_doc_comments: bool,
     pub fatal_errs: Vec<DiagnosticBuilder<'a>>,
@@ -100,6 +101,7 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler,
         /* dummy values, never read: */
         cur_tok: token::Eof,
         cur_span: DUMMY_SP,
+        next_tok: None,
         fatal_errs: Vec::new(),
     };
     tt_next_token(&mut r); /* get cur_tok and cur_span set up */
@@ -178,6 +180,9 @@ fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
 /// Return the next token from the TtReader.
 /// EFFECT: advances the reader's token field
 pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
+    if let Some(tok) = r.next_tok.take() {
+        return tok;
+    }
     // FIXME(pcwalton): Bad copy?
     let ret_val = TokenAndSpan {
         tok: r.cur_tok.clone(),
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index aca41bd7b59..e62d0d925cd 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -144,7 +144,7 @@ impl<'a> Reader for StringReader<'a> {
 
 impl<'a> Reader for TtReader<'a> {
     fn is_eof(&self) -> bool {
-        self.cur_tok == token::Eof
+        self.peek().tok == token::Eof
     }
     fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
         assert!(self.fatal_errs.is_empty());
@@ -165,10 +165,31 @@ impl<'a> Reader for TtReader<'a> {
         self.fatal_errs.clear();
     }
     fn peek(&self) -> TokenAndSpan {
-        TokenAndSpan {
+        self.next_tok.clone().unwrap_or(TokenAndSpan {
             tok: self.cur_tok.clone(),
             sp: self.cur_span,
-        }
+        })
+    }
+}
+
+impl<'a, 'b> Reader for &'b mut TtReader<'a> {
+    fn is_eof(&self) -> bool {
+        (**self).is_eof()
+    }
+    fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
+        (**self).try_next_token()
+    }
+    fn fatal(&self, m: &str) -> FatalError {
+        (**self).fatal(m)
+    }
+    fn err(&self, m: &str) {
+        (**self).err(m)
+    }
+    fn emit_fatal_errors(&mut self) {
+        (**self).emit_fatal_errors()
+    }
+    fn peek(&self) -> TokenAndSpan {
+        (**self).peek()
     }
 }