From 0ea65e0bcd98403bddf49ed4641ec47c32624ad5 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sat, 4 Oct 2025 10:37:22 -0500 Subject: [PATCH] Break out some parsing cold functions This recovers some instruction count regressions after changing most Pat parsing functions return a non-boxed Pat. It seems to be beneficial to break out a #[cold] parsing recovery function when the function includes more parsing, presumably because this requires more stack space and/or mem copies when LLVM optimizes the wrong path. --- .../rustc_parse/src/parser/diagnostics.rs | 26 ++++++++++++------- compiler/rustc_parse/src/parser/pat.rs | 21 +++++++-------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9e9a31d80474..c36cd610c6a5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1845,15 +1845,17 @@ impl<'a> Parser<'a> { &mut self, base: T, ) -> PResult<'a, T> { - if !self.may_recover() { - return Ok(base); - } - // Do not add `::` to expected tokens. - if self.token == token::PathSep { - if let Some(ty) = base.to_ty() { - return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); - } + if self.may_recover() && self.token == token::PathSep { + return self.recover_from_bad_qpath(base); + } + Ok(base) + } + + #[cold] + fn recover_from_bad_qpath(&mut self, base: T) -> PResult<'a, T> { + if let Some(ty) = base.to_ty() { + return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); } Ok(base) } @@ -2370,6 +2372,7 @@ impl<'a> Parser<'a> { None } + #[cold] pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (Box, Box)> { let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?; self.expect(exp!(Colon))?; @@ -2750,7 +2753,8 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - pub(crate) fn maybe_recover_colon_colon_in_pat_typo( + #[cold] + pub(crate) fn recover_colon_colon_in_pat_typo( &mut self, mut first_pat: Pat, expected: Option, @@ -2935,7 +2939,11 @@ impl<'a> Parser<'a> { if self.token != token::Comma { return Ok(()); } + self.recover_unexpected_comma(lo, rt) + } + #[cold] + fn recover_unexpected_comma(&mut self, lo: Span, rt: CommaRecoveryMode) -> PResult<'a, ()> { // An unexpected comma after a top-level pattern is a clue that the // user (perhaps more accustomed to some other language) forgot the // parentheses in what should have been a tuple pattern; return a diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 3ef772af97dd..4f522d57e414 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -199,8 +199,8 @@ impl<'a> Parser<'a> { // This complicated procedure is done purely for diagnostics UX. // Check if the user wrote `foo:bar` instead of `foo::bar`. - if ra == RecoverColon::Yes { - first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected); + if ra == RecoverColon::Yes && token::Colon == self.token.kind { + first_pat = self.recover_colon_colon_in_pat_typo(first_pat, expected); } if let Some(leading_vert_span) = leading_vert_span { @@ -874,9 +874,12 @@ impl<'a> Parser<'a> { } }; - let pat = self.mk_pat(lo.to(self.prev_token.span), pat); - let pat = self.maybe_recover_from_bad_qpath(pat)?; - let pat = self.recover_intersection_pat(pat)?; + let mut pat = self.mk_pat(lo.to(self.prev_token.span), pat); + + pat = self.maybe_recover_from_bad_qpath(pat)?; + if self.eat_noexpect(&token::At) { + pat = self.recover_intersection_pat(pat)?; + } if !allow_range_pat { self.ban_pat_range_if_ambiguous(&pat) @@ -922,14 +925,8 @@ impl<'a> Parser<'a> { /// e.g. [F#][and] where they are called AND-patterns. /// /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching + #[cold] fn recover_intersection_pat(&mut self, lhs: Pat) -> PResult<'a, Pat> { - if self.token != token::At { - // Next token is not `@` so it's not going to be an intersection pattern. - return Ok(lhs); - } - - // At this point we attempt to parse `@ $pat_rhs` and emit an error. - self.bump(); // `@` let mut rhs = self.parse_pat_no_top_alt(None, None)?; let whole_span = lhs.span.to(rhs.span);