Skip to content

Commit 6817442

Browse files
committed
Split NamedMatch::MatchNonterminal in two.
The `Lrc` is only relevant within `transcribe()`. There, the `Lrc` is helpful for the non-`NtTT` cases, because the entire nonterminal is cloned. But for the `NtTT` cases the inner token tree is cloned (a full clone) and so the `Lrc` is of no help. This commit splits the `NtTT` and non-`NtTT` cases, avoiding the useless `Lrc` in the former case, for the following effect on macro-heavy crates. - It reduces the total number of allocations a lot. - It increases the size of some of the remaining allocations. - It doesn't affect *peak* memory usage, because the larger allocations are short-lived. This overall gives a speed win.
1 parent 904e70a commit 6817442

File tree

3 files changed

+81
-71
lines changed

3 files changed

+81
-71
lines changed

compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ type NamedMatchVec = SmallVec<[NamedMatch; 4]>;
105105

106106
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
107107
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
108-
rustc_data_structures::static_assert_size!(NamedMatchVec, 72);
108+
rustc_data_structures::static_assert_size!(NamedMatchVec, 168);
109109

110110
/// Represents a single "position" (aka "matcher position", aka "item"), as
111111
/// described in the module documentation.
@@ -278,22 +278,20 @@ pub(super) fn count_names(ms: &[TokenTree]) -> usize {
278278
})
279279
}
280280

281-
/// `NamedMatch` is a pattern-match result for a single `token::MATCH_NONTERMINAL`:
282-
/// so it is associated with a single ident in a parse, and all
283-
/// `MatchedNonterminal`s in the `NamedMatch` have the same non-terminal type
284-
/// (expr, item, etc). Each leaf in a single `NamedMatch` corresponds to a
285-
/// single `token::MATCH_NONTERMINAL` in the `TokenTree` that produced it.
281+
/// `NamedMatch` is a pattern-match result for a single metavar. All
282+
/// `MatchedNtNonTt`s in the `NamedMatch` have the same non-terminal type
283+
/// (expr, item, etc).
286284
///
287285
/// The in-memory structure of a particular `NamedMatch` represents the match
288286
/// that occurred when a particular subset of a matcher was applied to a
289287
/// particular token tree.
290288
///
291289
/// The width of each `MatchedSeq` in the `NamedMatch`, and the identity of
292-
/// the `MatchedNonterminal`s, will depend on the token tree it was applied
293-
/// to: each `MatchedSeq` corresponds to a single `TTSeq` in the originating
290+
/// the `MatchedNtNonTts`s, will depend on the token tree it was applied
291+
/// to: each `MatchedSeq` corresponds to a single repetition in the originating
294292
/// token tree. The depth of the `NamedMatch` structure will therefore depend
295-
/// only on the nesting depth of `ast::TTSeq`s in the originating
296-
/// token tree it was derived from.
293+
/// only on the nesting depth of repetitions in the originating token tree it
294+
/// was derived from.
297295
///
298296
/// In layman's terms: `NamedMatch` will form a tree representing nested matches of a particular
299297
/// meta variable. For example, if we are matching the following macro against the following
@@ -312,24 +310,32 @@ pub(super) fn count_names(ms: &[TokenTree]) -> usize {
312310
/// ```rust
313311
/// MatchedSeq([
314312
/// MatchedSeq([
315-
/// MatchedNonterminal(a),
316-
/// MatchedNonterminal(b),
317-
/// MatchedNonterminal(c),
318-
/// MatchedNonterminal(d),
313+
/// MatchedNtNonTt(a),
314+
/// MatchedNtNonTt(b),
315+
/// MatchedNtNonTt(c),
316+
/// MatchedNtNonTt(d),
319317
/// ]),
320318
/// MatchedSeq([
321-
/// MatchedNonterminal(a),
322-
/// MatchedNonterminal(b),
323-
/// MatchedNonterminal(c),
324-
/// MatchedNonterminal(d),
325-
/// MatchedNonterminal(e),
319+
/// MatchedNtNonTt(a),
320+
/// MatchedNtNonTt(b),
321+
/// MatchedNtNonTt(c),
322+
/// MatchedNtNonTt(d),
323+
/// MatchedNtNonTt(e),
326324
/// ])
327325
/// ])
328326
/// ```
329327
#[derive(Debug, Clone)]
330328
crate enum NamedMatch {
331329
MatchedSeq(Lrc<NamedMatchVec>),
332-
MatchedNonterminal(Lrc<Nonterminal>),
330+
331+
// This variant should never hold an `NtTT`. `MatchedNtTt` should be used
332+
// for that case.
333+
MatchedNtNonTt(Lrc<Nonterminal>),
334+
335+
// `NtTT` is handled without any cloning when transcribing, unlike other
336+
// nonterminals. Therefore, an `Lrc` isn't helpful and causes unnecessary
337+
// allocations. Hence this separate variant.
338+
MatchedNtTt(rustc_ast::tokenstream::TokenTree),
333339
}
334340

335341
/// Takes a slice of token trees `ms` representing a matcher which successfully matched input
@@ -669,7 +675,11 @@ impl<'tt> TtParser<'tt> {
669675
}
670676
Ok(nt) => nt,
671677
};
672-
item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
678+
let m = match nt {
679+
Nonterminal::NtTT(tt) => MatchedNtTt(tt),
680+
_ => MatchedNtNonTt(Lrc::new(nt)),
681+
};
682+
item.push_match(match_cur, m);
673683
item.idx += 1;
674684
item.match_cur += 1;
675685
} else {

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstF
44
use crate::mbe;
55
use crate::mbe::macro_check;
66
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
7-
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq};
7+
use crate::mbe::macro_parser::{MatchedNtTt, MatchedSeq};
88
use crate::mbe::transcribe::transcribe;
99

1010
use rustc_ast as ast;
11-
use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
11+
use rustc_ast::token::{self, NonterminalKind, Token, TokenKind::*};
1212
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
1313
use rustc_ast::{NodeId, DUMMY_NODE_ID};
1414
use rustc_ast_pretty::pprust;
@@ -470,22 +470,20 @@ pub fn compile_declarative_macro(
470470
MatchedSeq(ref s) => s
471471
.iter()
472472
.map(|m| {
473-
if let MatchedNonterminal(ref nt) = *m {
474-
if let NtTT(ref tt) = **nt {
475-
let mut tts = vec![];
476-
mbe::quoted::parse(
477-
tt.clone().into(),
478-
true,
479-
&sess.parse_sess,
480-
def.id,
481-
features,
482-
edition,
483-
&mut tts,
484-
);
485-
let tt = tts.pop().unwrap();
486-
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
487-
return tt;
488-
}
473+
if let MatchedNtTt(ref tt) = *m {
474+
let mut tts = vec![];
475+
mbe::quoted::parse(
476+
tt.clone().into(),
477+
true,
478+
&sess.parse_sess,
479+
def.id,
480+
features,
481+
edition,
482+
&mut tts,
483+
);
484+
let tt = tts.pop().unwrap();
485+
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
486+
return tt;
489487
}
490488
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
491489
})
@@ -497,20 +495,18 @@ pub fn compile_declarative_macro(
497495
MatchedSeq(ref s) => s
498496
.iter()
499497
.map(|m| {
500-
if let MatchedNonterminal(ref nt) = *m {
501-
if let NtTT(ref tt) = **nt {
502-
let mut tts = vec![];
503-
mbe::quoted::parse(
504-
tt.clone().into(),
505-
false,
506-
&sess.parse_sess,
507-
def.id,
508-
features,
509-
edition,
510-
&mut tts,
511-
);
512-
return tts.pop().unwrap();
513-
}
498+
if let MatchedNtTt(ref tt) = *m {
499+
let mut tts = vec![];
500+
mbe::quoted::parse(
501+
tt.clone().into(),
502+
false,
503+
&sess.parse_sess,
504+
def.id,
505+
features,
506+
edition,
507+
&mut tts,
508+
);
509+
return tts.pop().unwrap();
514510
}
515511
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
516512
})

compiler/rustc_expand/src/mbe/transcribe.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::base::ExtCtxt;
2-
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
2+
use crate::mbe::macro_parser::{MatchedNtNonTt, MatchedNtTt, MatchedSeq, NamedMatch};
33
use crate::mbe::{self, MetaVarExpr};
44
use rustc_ast::mut_visit::{self, MutVisitor};
5-
use rustc_ast::token::{self, NtTT, Token, TokenKind};
5+
use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
66
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_data_structures::sync::Lrc;
@@ -233,25 +233,29 @@ pub(super) fn transcribe<'a>(
233233
// the meta-var.
234234
let ident = MacroRulesNormalizedIdent::new(orignal_ident);
235235
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
236-
if let MatchedNonterminal(nt) = cur_matched {
237-
let token = if let NtTT(tt) = &**nt {
236+
match cur_matched {
237+
MatchedNtTt(ref tt) => {
238238
// `tt`s are emitted into the output stream directly as "raw tokens",
239239
// without wrapping them into groups.
240-
tt.clone()
241-
} else {
240+
let token = tt.clone();
241+
result.push(token.into());
242+
}
243+
MatchedNtNonTt(ref nt) => {
242244
// Other variables are emitted into the output stream as groups with
243245
// `Delimiter::None` to maintain parsing priorities.
244246
// `Interpolated` is currently used for such groups in rustc parser.
247+
debug_assert!(!matches!(**nt, Nonterminal::NtTT(_)));
245248
marker.visit_span(&mut sp);
246-
TokenTree::token(token::Interpolated(nt.clone()), sp)
247-
};
248-
result.push(token.into());
249-
} else {
250-
// We were unable to descend far enough. This is an error.
251-
return Err(cx.struct_span_err(
252-
sp, /* blame the macro writer */
253-
&format!("variable '{}' is still repeating at this depth", ident),
254-
));
249+
let token = TokenTree::token(token::Interpolated(nt.clone()), sp);
250+
result.push(token.into());
251+
}
252+
MatchedSeq(..) => {
253+
// We were unable to descend far enough. This is an error.
254+
return Err(cx.struct_span_err(
255+
sp, /* blame the macro writer */
256+
&format!("variable '{}' is still repeating at this depth", ident),
257+
));
258+
}
255259
}
256260
} else {
257261
// If we aren't able to match the meta-var, we push it back into the result but
@@ -308,7 +312,7 @@ fn lookup_cur_matched<'a>(
308312
let mut matched = matched;
309313
for &(idx, _) in repeats {
310314
match matched {
311-
MatchedNonterminal(_) => break,
315+
MatchedNtTt(_) | MatchedNtNonTt(_) => break,
312316
MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
313317
}
314318
}
@@ -398,7 +402,7 @@ fn lockstep_iter_size(
398402
let name = MacroRulesNormalizedIdent::new(name);
399403
match lookup_cur_matched(name, interpolations, repeats) {
400404
Some(matched) => match matched {
401-
MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
405+
MatchedNtTt(_) | MatchedNtNonTt(_) => LockstepIterSize::Unconstrained,
402406
MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
403407
},
404408
_ => LockstepIterSize::Unconstrained,
@@ -445,7 +449,7 @@ fn count_repetitions<'a>(
445449
sp: &DelimSpan,
446450
) -> PResult<'a, usize> {
447451
match matched {
448-
MatchedNonterminal(_) => {
452+
MatchedNtTt(_) | MatchedNtNonTt(_) => {
449453
if declared_lhs_depth == 0 {
450454
return Err(cx.struct_span_err(
451455
sp.entire(),

0 commit comments

Comments
 (0)