Skip to content

Commit 094eaf0

Browse files
authored
Rollup merge of rust-lang#37208 - jseyfried:fix_partially_consumed_tokens_in_macros, r=nrc
macros: fix partially consumed tokens in macro matchers Fixes rust-lang#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 rust-lang#34630 by ~8%. r? @nrc
2 parents 4568318 + 95a9e2a commit 094eaf0

File tree

4 files changed

+52
-15
lines changed

4 files changed

+52
-15
lines changed

src/libsyntax/ext/tt/macro_parser.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -476,24 +476,21 @@ pub fn parse(sess: &ParseSess,
476476
}
477477
rdr.next_token();
478478
} else /* bb_eis.len() == 1 */ {
479-
let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(rdr.clone()));
480-
481-
let mut ei = bb_eis.pop().unwrap();
482-
match ei.top_elts.get_tt(ei.idx) {
483-
TokenTree::Token(span, MatchNt(_, ident)) => {
479+
rdr.next_tok = {
480+
let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(&mut rdr));
481+
let mut ei = bb_eis.pop().unwrap();
482+
if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) {
484483
let match_cur = ei.match_cur;
485484
(&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal(
486485
parse_nt(&mut rust_parser, span, &ident.name.as_str()))));
487486
ei.idx += 1;
488487
ei.match_cur += 1;
488+
} else {
489+
unreachable!()
489490
}
490-
_ => panic!()
491-
}
492-
cur_eis.push(ei);
493-
494-
for _ in 0..rust_parser.tokens_consumed {
495-
let _ = rdr.next_token();
496-
}
491+
cur_eis.push(ei);
492+
Some(TokenAndSpan { tok: rust_parser.token, sp: rust_parser.span })
493+
};
497494
}
498495
}
499496

src/libsyntax/ext/tt/transcribe.rs

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub struct TtReader<'a> {
4848
/* cached: */
4949
pub cur_tok: Token,
5050
pub cur_span: Span,
51+
pub next_tok: Option<TokenAndSpan>,
5152
/// Transform doc comments. Only useful in macro invocations
5253
pub desugar_doc_comments: bool,
5354
pub fatal_errs: Vec<DiagnosticBuilder<'a>>,
@@ -100,6 +101,7 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler,
100101
/* dummy values, never read: */
101102
cur_tok: token::Eof,
102103
cur_span: DUMMY_SP,
104+
next_tok: None,
103105
fatal_errs: Vec::new(),
104106
};
105107
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 {
178180
/// Return the next token from the TtReader.
179181
/// EFFECT: advances the reader's token field
180182
pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
183+
if let Some(tok) = r.next_tok.take() {
184+
return tok;
185+
}
181186
// FIXME(pcwalton): Bad copy?
182187
let ret_val = TokenAndSpan {
183188
tok: r.cur_tok.clone(),

src/libsyntax/parse/lexer/mod.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl<'a> Reader for StringReader<'a> {
144144

145145
impl<'a> Reader for TtReader<'a> {
146146
fn is_eof(&self) -> bool {
147-
self.cur_tok == token::Eof
147+
self.peek().tok == token::Eof
148148
}
149149
fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
150150
assert!(self.fatal_errs.is_empty());
@@ -165,10 +165,31 @@ impl<'a> Reader for TtReader<'a> {
165165
self.fatal_errs.clear();
166166
}
167167
fn peek(&self) -> TokenAndSpan {
168-
TokenAndSpan {
168+
self.next_tok.clone().unwrap_or(TokenAndSpan {
169169
tok: self.cur_tok.clone(),
170170
sp: self.cur_span,
171-
}
171+
})
172+
}
173+
}
174+
175+
impl<'a, 'b> Reader for &'b mut TtReader<'a> {
176+
fn is_eof(&self) -> bool {
177+
(**self).is_eof()
178+
}
179+
fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
180+
(**self).try_next_token()
181+
}
182+
fn fatal(&self, m: &str) -> FatalError {
183+
(**self).fatal(m)
184+
}
185+
fn err(&self, m: &str) {
186+
(**self).err(m)
187+
}
188+
fn emit_fatal_errors(&mut self) {
189+
(**self).emit_fatal_errors()
190+
}
191+
fn peek(&self) -> TokenAndSpan {
192+
(**self).peek()
172193
}
173194
}
174195

src/test/run-pass/issue-37175.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
macro_rules! m { (<$t:ty>) => { stringify!($t) } }
12+
fn main() {
13+
println!("{}", m!(<Vec<i32>>));
14+
}

0 commit comments

Comments
 (0)