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.
This commit is contained in:
Cameron Steffen
2025-10-04 10:37:22 -05:00
parent 703584604a
commit 0ea65e0bcd
2 changed files with 26 additions and 21 deletions

View File

@@ -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<T: RecoverQPath>(&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<ast::Pat>, Box<ast::Ty>)> {
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<Expected>,
@@ -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

View File

@@ -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);