Skip to content

Commit b7b7f27

Browse files
committed
Auto merge of #103898 - Nilstrieb:match-macro, r=nnethercote
Retry failed macro matching for diagnostics When a declarative macro fails to match, retry the matching to collect diagnostic info instead of collecting it on the fly in the hot path. Split out of #103439. You made a bunch of changes to declarative macro matching, so r? `@nnethercote` This change should produce a few small perf wins: #103439 (comment)
2 parents 5b82ea7 + ebfa2ab commit b7b7f27

File tree

3 files changed

+289
-143
lines changed

3 files changed

+289
-143
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

+32-21
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,17 @@
7373
pub(crate) use NamedMatch::*;
7474
pub(crate) use ParseResult::*;
7575

76-
use crate::mbe::{KleeneOp, TokenTree};
76+
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
7777

7878
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
79+
use rustc_data_structures::fx::FxHashMap;
80+
use rustc_data_structures::sync::Lrc;
81+
use rustc_errors::ErrorGuaranteed;
7982
use rustc_lint_defs::pluralize;
8083
use rustc_parse::parser::{NtOrTt, Parser};
84+
use rustc_span::symbol::Ident;
8185
use rustc_span::symbol::MacroRulesNormalizedIdent;
8286
use rustc_span::Span;
83-
84-
use rustc_data_structures::fx::FxHashMap;
85-
use rustc_data_structures::sync::Lrc;
86-
use rustc_span::symbol::Ident;
8787
use std::borrow::Cow;
8888
use std::collections::hash_map::Entry::{Occupied, Vacant};
8989

@@ -96,7 +96,8 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
9696
///
9797
/// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
9898
/// simply incrementing the current matcher position index by one.
99-
pub(super) enum MatcherLoc {
99+
#[derive(Debug)]
100+
pub(crate) enum MatcherLoc {
100101
Token {
101102
token: Token,
102103
},
@@ -270,13 +271,17 @@ pub(crate) enum ParseResult<T> {
270271
Failure(Token, &'static str),
271272
/// Fatal error (malformed macro?). Abort compilation.
272273
Error(rustc_span::Span, String),
273-
ErrorReported,
274+
ErrorReported(ErrorGuaranteed),
274275
}
275276

276277
/// A `ParseResult` where the `Success` variant contains a mapping of
277278
/// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
278279
/// of metavars to the token trees they bind to.
279-
pub(crate) type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>;
280+
pub(crate) type NamedParseResult = ParseResult<NamedMatches>;
281+
282+
/// Contains a mapping of `MacroRulesNormalizedIdent`s to `NamedMatch`es.
283+
/// This represents the mapping of metavars to the token trees they bind to.
284+
pub(crate) type NamedMatches = FxHashMap<MacroRulesNormalizedIdent, NamedMatch>;
280285

281286
/// Count how many metavars declarations are in `matcher`.
282287
pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
@@ -400,17 +405,21 @@ impl TtParser {
400405
///
401406
/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
402407
/// track of through the mps generated.
403-
fn parse_tt_inner(
408+
fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
404409
&mut self,
405-
matcher: &[MatcherLoc],
410+
matcher: &'matcher [MatcherLoc],
406411
token: &Token,
412+
track: &mut T,
407413
) -> Option<NamedParseResult> {
408414
// Matcher positions that would be valid if the macro invocation was over now. Only
409415
// modified if `token == Eof`.
410416
let mut eof_mps = EofMatcherPositions::None;
411417

412418
while let Some(mut mp) = self.cur_mps.pop() {
413-
match &matcher[mp.idx] {
419+
let matcher_loc = &matcher[mp.idx];
420+
track.before_match_loc(self, matcher_loc);
421+
422+
match matcher_loc {
414423
MatcherLoc::Token { token: t } => {
415424
// If it's a doc comment, we just ignore it and move on to the next tt in the
416425
// matcher. This is a bug, but #95267 showed that existing programs rely on
@@ -450,7 +459,7 @@ impl TtParser {
450459
// Try zero matches of this sequence, by skipping over it.
451460
self.cur_mps.push(MatcherPos {
452461
idx: idx_first_after,
453-
matches: mp.matches.clone(), // a cheap clone
462+
matches: Lrc::clone(&mp.matches),
454463
});
455464
}
456465

@@ -463,8 +472,8 @@ impl TtParser {
463472
// sequence. If that's not possible, `ending_mp` will fail quietly when it is
464473
// processed next time around the loop.
465474
let ending_mp = MatcherPos {
466-
idx: mp.idx + 1, // +1 skips the Kleene op
467-
matches: mp.matches.clone(), // a cheap clone
475+
idx: mp.idx + 1, // +1 skips the Kleene op
476+
matches: Lrc::clone(&mp.matches),
468477
};
469478
self.cur_mps.push(ending_mp);
470479

@@ -479,8 +488,8 @@ impl TtParser {
479488
// separator yet. Try ending the sequence. If that's not possible, `ending_mp`
480489
// will fail quietly when it is processed next time around the loop.
481490
let ending_mp = MatcherPos {
482-
idx: mp.idx + 2, // +2 skips the separator and the Kleene op
483-
matches: mp.matches.clone(), // a cheap clone
491+
idx: mp.idx + 2, // +2 skips the separator and the Kleene op
492+
matches: Lrc::clone(&mp.matches),
484493
};
485494
self.cur_mps.push(ending_mp);
486495

@@ -552,10 +561,11 @@ impl TtParser {
552561
}
553562

554563
/// Match the token stream from `parser` against `matcher`.
555-
pub(super) fn parse_tt(
564+
pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
556565
&mut self,
557566
parser: &mut Cow<'_, Parser<'_>>,
558-
matcher: &[MatcherLoc],
567+
matcher: &'matcher [MatcherLoc],
568+
track: &mut T,
559569
) -> NamedParseResult {
560570
// A queue of possible matcher positions. We initialize it with the matcher position in
561571
// which the "dot" is before the first token of the first token tree in `matcher`.
@@ -571,7 +581,8 @@ impl TtParser {
571581

572582
// Process `cur_mps` until either we have finished the input or we need to get some
573583
// parsing from the black-box parser done.
574-
if let Some(res) = self.parse_tt_inner(matcher, &parser.token) {
584+
let res = self.parse_tt_inner(matcher, &parser.token, track);
585+
if let Some(res) = res {
575586
return res;
576587
}
577588

@@ -612,14 +623,14 @@ impl TtParser {
612623
// edition-specific matching behavior for non-terminals.
613624
let nt = match parser.to_mut().parse_nonterminal(kind) {
614625
Err(mut err) => {
615-
err.span_label(
626+
let guarantee = err.span_label(
616627
span,
617628
format!(
618629
"while parsing argument for this `{kind}` macro fragment"
619630
),
620631
)
621632
.emit();
622-
return ErrorReported;
633+
return ErrorReported(guarantee);
623634
}
624635
Ok(nt) => nt,
625636
};

0 commit comments

Comments
 (0)