Skip to content

Commit 2f8a068

Browse files
committed
Add Tracker to track matching operations
This should allow us to collect detailed information without slowing down the inital hot path.
1 parent 6c47848 commit 2f8a068

File tree

3 files changed

+48
-17
lines changed

3 files changed

+48
-17
lines changed

compiler/rustc_expand/src/mbe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl KleeneToken {
5252
/// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star)
5353
/// for token sequences.
5454
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
55-
enum KleeneOp {
55+
pub(crate) enum KleeneOp {
5656
/// Kleene star (`*`) for zero or more repetitions
5757
ZeroOrMore,
5858
/// Kleene plus (`+`) for one or more repetitions

compiler/rustc_expand/src/mbe/macro_parser.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,20 @@
7070
//! eof: [a $( a )* a b ·]
7171
//! ```
7272
73+
use rustc_errors::ErrorGuaranteed;
7374
pub(crate) use NamedMatch::*;
7475
pub(crate) use ParseResult::*;
75-
use rustc_errors::ErrorGuaranteed;
7676

77-
use crate::mbe::{KleeneOp, TokenTree};
77+
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
7878

7979
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
80+
use rustc_data_structures::fx::FxHashMap;
81+
use rustc_data_structures::sync::Lrc;
8082
use rustc_lint_defs::pluralize;
8183
use rustc_parse::parser::{NtOrTt, Parser};
84+
use rustc_span::symbol::Ident;
8285
use rustc_span::symbol::MacroRulesNormalizedIdent;
8386
use rustc_span::Span;
84-
85-
use rustc_data_structures::fx::FxHashMap;
86-
use rustc_data_structures::sync::Lrc;
87-
use rustc_span::symbol::Ident;
8887
use std::borrow::Cow;
8988
use std::collections::hash_map::Entry::{Occupied, Vacant};
9089

@@ -97,7 +96,8 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
9796
///
9897
/// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
9998
/// simply incrementing the current matcher position index by one.
100-
pub(super) enum MatcherLoc {
99+
#[derive(Debug, Clone, PartialEq)]
100+
pub(crate) enum MatcherLoc {
101101
Token {
102102
token: Token,
103103
},
@@ -401,17 +401,21 @@ impl TtParser {
401401
///
402402
/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
403403
/// track of through the mps generated.
404-
fn parse_tt_inner(
404+
fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
405405
&mut self,
406-
matcher: &[MatcherLoc],
406+
matcher: &'matcher [MatcherLoc],
407407
token: &Token,
408+
track: &mut T,
408409
) -> Option<NamedParseResult> {
409410
// Matcher positions that would be valid if the macro invocation was over now. Only
410411
// modified if `token == Eof`.
411412
let mut eof_mps = EofMatcherPositions::None;
412413

413414
while let Some(mut mp) = self.cur_mps.pop() {
414-
match &matcher[mp.idx] {
415+
let matcher_loc = &matcher[mp.idx];
416+
track.before_match_loc(self, matcher_loc);
417+
418+
match matcher_loc {
415419
MatcherLoc::Token { token: t } => {
416420
// If it's a doc comment, we just ignore it and move on to the next tt in the
417421
// matcher. This is a bug, but #95267 showed that existing programs rely on
@@ -553,10 +557,11 @@ impl TtParser {
553557
}
554558

555559
/// Match the token stream from `parser` against `matcher`.
556-
pub(super) fn parse_tt(
560+
pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
557561
&mut self,
558562
parser: &mut Cow<'_, Parser<'_>>,
559-
matcher: &[MatcherLoc],
563+
matcher: &'matcher [MatcherLoc],
564+
track: &mut T,
560565
) -> NamedParseResult {
561566
// A queue of possible matcher positions. We initialize it with the matcher position in
562567
// which the "dot" is before the first token of the first token tree in `matcher`.
@@ -572,7 +577,8 @@ impl TtParser {
572577

573578
// Process `cur_mps` until either we have finished the input or we need to get some
574579
// parsing from the black-box parser done.
575-
if let Some(res) = self.parse_tt_inner(matcher, &parser.token) {
580+
let res = self.parse_tt_inner(matcher, &parser.token, track);
581+
if let Some(res) = res {
576582
return res;
577583
}
578584

compiler/rustc_expand/src/mbe/macro_rules.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ use std::borrow::Cow;
3333
use std::collections::hash_map::Entry;
3434
use std::{mem, slice};
3535

36+
use super::macro_parser::NamedParseResult;
37+
3638
pub(crate) struct ParserAnyMacro<'a> {
3739
parser: Parser<'a>,
3840

@@ -205,6 +207,29 @@ fn trace_macros_note(cx_expansions: &mut FxIndexMap<Span, Vec<String>>, sp: Span
205207
cx_expansions.entry(sp).or_default().push(message);
206208
}
207209

210+
pub(super) trait Tracker<'matcher> {
211+
/// This is called before trying to match next MatcherLoc on the current token
212+
fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc);
213+
214+
/// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
215+
/// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`)
216+
fn after_arm(&mut self, result: &NamedParseResult);
217+
218+
/// For tracing
219+
fn description() -> &'static str;
220+
}
221+
222+
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization
223+
struct NoopTracker;
224+
225+
impl<'matcher> Tracker<'matcher> for NoopTracker {
226+
fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {}
227+
fn after_arm(&mut self, _: &NamedParseResult) {}
228+
fn description() -> &'static str {
229+
"none"
230+
}
231+
}
232+
208233
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
209234
/// input `arg`.
210235
fn expand_macro<'cx>(
@@ -262,7 +287,7 @@ fn expand_macro<'cx>(
262287
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
263288
let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
264289

265-
match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs) {
290+
match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) {
266291
Success(named_matches) => {
267292
// The matcher was `Success(..)`ful.
268293
// Merge the gated spans from parsing the matcher with the pre-existing ones.
@@ -354,7 +379,7 @@ fn expand_macro<'cx>(
354379
if let Some((arg, comma_span)) = arg.add_comma() {
355380
for lhs in lhses {
356381
let parser = parser_from_cx(sess, arg.clone());
357-
if let Success(_) = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs) {
382+
if let Success(_) = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) {
358383
if comma_span.is_dummy() {
359384
err.note("you might be missing a comma");
360385
} else {
@@ -452,7 +477,7 @@ pub fn compile_declarative_macro(
452477
let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
453478
let mut tt_parser =
454479
TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
455-
let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
480+
let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram, &mut NoopTracker) {
456481
Success(m) => m,
457482
Failure(token, msg) => {
458483
let s = parse_failure_msg(&token);

0 commit comments

Comments
 (0)