Skip to content

Commit 14e57d7

Browse files
committed
perform TokenStream replacement in-place when possible in expand_macro
1 parent 6162f6f commit 14e57d7

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

compiler/rustc_ast/src/tokenstream.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
2525
use rustc_span::{Span, DUMMY_SP};
2626
use smallvec::{smallvec, SmallVec};
2727

28-
use std::{fmt, iter};
28+
use std::{fmt, iter, mem};
2929

3030
/// When the main Rust parser encounters a syntax-extension invocation, it
3131
/// parses the arguments to the invocation as a token tree. This is a very
@@ -410,8 +410,23 @@ impl TokenStream {
410410
t1.next().is_none() && t2.next().is_none()
411411
}
412412

413-
pub fn map_enumerated<F: FnMut(usize, &TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
414-
TokenStream(Lrc::new(self.0.iter().enumerate().map(|(i, tree)| f(i, tree)).collect()))
413+
/// Applies the supplied function to each `TokenTree` and its index in `self`, returning a new `TokenStream`
414+
///
415+
/// It is equivalent to `TokenStream::new(self.trees().cloned().enumerate().map(|(i, tt)| f(i, tt)).collect())`.
416+
pub fn map_enumerated_owned(
417+
mut self,
418+
mut f: impl FnMut(usize, TokenTree) -> TokenTree,
419+
) -> TokenStream {
420+
if let Some(inner) = Lrc::get_mut(&mut self.0) {
421+
// optimization: perform the map in-place if self's reference count is 1
422+
let owned = mem::take(inner);
423+
*inner = owned.into_iter().enumerate().map(|(i, tree)| f(i, tree)).collect();
424+
self
425+
} else {
426+
TokenStream(Lrc::new(
427+
self.0.iter().enumerate().map(|(i, tree)| f(i, tree.clone())).collect(),
428+
))
429+
}
415430
}
416431

417432
/// Create a token stream containing a single token with alone spacing.

compiler/rustc_expand/src/mbe/macro_rules.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,7 @@ fn expand_macro<'cx>(
223223
// Replace all the tokens for the corresponding positions in the macro, to maintain
224224
// proper positions in error reporting, while maintaining the macro_backtrace.
225225
if tts.len() == rhs.tts.len() {
226-
tts = tts.map_enumerated(|i, tt| {
227-
let mut tt = tt.clone();
226+
tts = tts.map_enumerated_owned(|i, mut tt| {
228227
let rhs_tt = &rhs.tts[i];
229228
let ctxt = tt.span().ctxt();
230229
match (&mut tt, rhs_tt) {

0 commit comments

Comments
 (0)