Skip to main content

rustc_parse/parser/
expr.rs

1// ignore-tidy-file-filelength
2
3use core::mem;
4use core::ops::{Bound, ControlFlow};
5
6use ast::mut_visit::{self, MutVisitor};
7use ast::token::IdentKind;
8use ast::{ForLoopKind, MatchKind, Pat, Path, PathSegment, Recovered};
9use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};
10use rustc_ast::util::case::Case;
11use rustc_ast::util::classify;
12use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
13use rustc_ast::visit::{Visitor, walk_expr};
14use rustc_ast::{
15    self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
16    BlockCheckMode, CaptureBy, ClosureBinder, CoroutineKind, DUMMY_NODE_ID, Expr, ExprField,
17    ExprKind, FnDecl, FnRetTy, ForLoop, Guard, Label, MacCall, MetaItemLit, Movability, Param,
18    RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
19};
20use rustc_ast_pretty::pprust;
21use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
22use rustc_lint_defs::builtin::BREAK_WITH_LABEL_AND_LOOP;
23use rustc_literal_escaper::unescape_char;
24use rustc_session::diagnostics::report_lit_error;
25use rustc_span::edition::Edition;
26use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym};
27use thin_vec::{ThinVec, thin_vec};
28use tracing::instrument;
29
30use super::diagnostics::SnapshotParser;
31use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
32use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
33use super::{
34    AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,
35    Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
36};
37use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
38
39pub(super) mod diagnostics;
40
41#[derive(#[automatically_derived]impl ::core::fmt::Debug for DestructuredFloat {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Single(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Single", __self_0, &__self_1),
            Self::TrailingDot(__self_0, __self_1, __self_2) =>
                ::core::fmt::Formatter::debug_struct_field3_finish(f,
                    "TrailingDot", __self_0, __self_1, &__self_2),
            Self::MiddleDot(__self_0, __self_1, __self_2, __self_3, __self_4)
                =>
                ::core::fmt::Formatter::debug_struct_field5_finish(f,
                    "MiddleDot", __self_0, __self_1, __self_2, __self_3,
                    &__self_4),
            Self::Error => ::core::fmt::Formatter::write_str(f, "Error"),
        }
    }
}Debug)]
42pub(super) enum DestructuredFloat {
43    /// 1e2
44    Single(Symbol, Span),
45    /// 1.
46    TrailingDot(Symbol, Span, Span),
47    /// 1.2 | 1.2e3
48    MiddleDot(Symbol, Span, Span, Symbol, Span),
49    /// Invalid
50    Error,
51}
52
53impl<'a> Parser<'a> {
54    /// Parses an expression.
55    #[inline]
56    pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> {
57        self.current_closure.take();
58        self.parse_expr_res(Restrictions::empty())
59    }
60    #[inline]
61    pub fn parse_expr_in_let(&mut self) -> PResult<'a, Box<Expr>> {
62        self.current_closure.take();
63        self.parse_expr_res(Restrictions::IN_LET)
64    }
65    /// Parses an expression, forcing tokens to be collected.
66    pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {
67        self.current_closure.take();
68
69        // If the expression is associative (e.g. `1 + 2`), then any preceding
70        // outer attribute actually belongs to the first inner sub-expression.
71        // In which case we must use the pre-attr pos to include the attribute
72        // in the collected tokens for the outer expression.
73        let pre_attr_pos = self.collect_pos();
74        let attrs = self.parse_outer_attributes()?;
75        self.collect_tokens(
76            Some(pre_attr_pos),
77            AttrWrapper::empty(),
78            ForceCollect::Yes,
79            |this, _empty_attrs| {
80                let (expr, is_assoc) =
81                    this.parse_expr_res_after_attrs(Restrictions::empty(), attrs)?;
82                let use_pre_attr_pos =
83                    if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
84                Ok((expr, Trailing::No, use_pre_attr_pos))
85            },
86        )
87    }
88
89    pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
90        self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
91    }
92
93    /// Parses a sequence of expressions delimited by parentheses.
94    fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {
95        self.parse_paren_comma_seq(Self::parse_expr).map(|(r, _)| r)
96    }
97
98    /// Parses an expression, subject to the given restrictions.
99    #[inline]
100    pub(super) fn parse_expr_res(&mut self, r: Restrictions) -> PResult<'a, Box<Expr>> {
101        let attrs = self.parse_outer_attributes()?;
102        self.parse_expr_res_after_attrs(r, attrs).map(|(expr, _)| expr)
103    }
104
105    /// Same as `parse_expr_res`, but with attributes already pre-parsed.
106    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
107    /// followed by a subexpression (e.g. `1 + 2`).
108    #[inline]
109    pub(super) fn parse_expr_res_after_attrs(
110        &mut self,
111        r: Restrictions,
112        attrs: AttrWrapper,
113    ) -> PResult<'a, (Box<Expr>, bool)> {
114        self.with_res(r, |this| this.parse_expr_assoc_after_attrs(Bound::Unbounded, attrs))
115    }
116
117    /// Parses an associative expression with operators of at least `min_prec` precedence.
118    pub(super) fn parse_expr_assoc(
119        &mut self,
120        min_prec: Bound<ExprPrecedence>,
121    ) -> PResult<'a, Box<Expr>> {
122        let attrs = self.parse_outer_attributes()?;
123        self.parse_expr_assoc_after_attrs(min_prec, attrs).map(|(expr, _)| expr)
124    }
125
126    /// Same as `parse_expr_assoc`, but with attributes already pre-parsed.
127    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
128    /// followed by a subexpression (e.g. `1 + 2`).
129    pub(super) fn parse_expr_assoc_after_attrs(
130        &mut self,
131        min_prec: Bound<ExprPrecedence>,
132        attrs: AttrWrapper,
133    ) -> PResult<'a, (Box<Expr>, bool)> {
134        let lhs = if self.token.is_range_separator() {
135            return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
136        } else {
137            self.parse_expr_prefix(attrs)?
138        };
139        self.parse_expr_assoc_rest(min_prec, false, lhs)
140    }
141
142    /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
143    /// of at least `min_prec` precedence. The `bool` in the return value indicates if something
144    /// was actually parsed.
145    pub(super) fn parse_expr_assoc_rest(
146        &mut self,
147        min_prec: Bound<ExprPrecedence>,
148        starts_stmt: bool,
149        mut lhs: Box<Expr>,
150    ) -> PResult<'a, (Box<Expr>, bool)> {
151        let mut parsed_something = false;
152        if self.expr_is_complete(&lhs) && !self.recover_from_bin_op_after_complete_stmt_expr(&lhs) {
153            return Ok((lhs, parsed_something));
154        }
155
156        self.expected_token_types.insert(TokenType::Operator);
157        while let Some(op) = self.check_assoc_op() {
158            let lhs_span = self.interpolated_or_expr_span(&lhs);
159            let restrictions = if op.node.is_assign_like() {
160                self.restrictions & Restrictions::NO_STRUCT_LITERAL
161            } else {
162                self.restrictions
163            };
164            let prec = op.node.precedence();
165            if match min_prec {
166                Bound::Included(min_prec) => prec < min_prec,
167                Bound::Excluded(min_prec) => prec <= min_prec,
168                Bound::Unbounded => false,
169            } {
170                break;
171            }
172
173            self.reject_dotdotdot_expr_op();
174            self.reject_larrow_expr_op();
175
176            parsed_something = true;
177            self.bump();
178
179            if op.node.is_comparison()
180                && let Some(expr) = self.check_no_chained_comparison(&lhs, &op)?
181            {
182                return Ok((expr, parsed_something));
183            }
184
185            self.recover_from_strict_eq_op(op);
186            self.recover_from_diamond_ne_op();
187            self.recover_from_spaceship_cmp_op();
188            self.recover_from_postfix_inc_op(&lhs, starts_stmt)?;
189            self.recover_from_postfix_dec_op(&lhs, starts_stmt)?;
190
191            let min_prec = match op.node.fixity() {
192                Fixity::Right => Bound::Included(prec),
193                Fixity::Left | Fixity::None => Bound::Excluded(prec),
194            };
195
196            let finish_parsing_bin_op = |this: &mut Self| {
197                let rhs = this.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
198                    this.parse_expr_assoc(min_prec)
199                })?;
200                let span = this.mk_expr_sp(&lhs, lhs_span, op.span, rhs.span);
201                Ok((rhs, span))
202            };
203
204            lhs = match op.node {
205                AssocOp::Binary(ast_op) => {
206                    let (rhs, span) = finish_parsing_bin_op(self)?;
207                    self.mk_expr(span, self.mk_binary(respan(op.span, ast_op), lhs, rhs))
208                }
209                AssocOp::AssignOp(aop) => {
210                    let (rhs, span) = finish_parsing_bin_op(self)?;
211                    self.mk_expr(span, self.mk_assign_op(respan(op.span, aop), lhs, rhs))
212                }
213                AssocOp::Assign => {
214                    let (rhs, span) = finish_parsing_bin_op(self)?;
215                    self.mk_expr(span, ExprKind::Assign(lhs, rhs, op.span))
216                }
217                AssocOp::Cast => self.parse_assoc_op_cast(lhs, lhs_span, op.span)?,
218                AssocOp::Range(limits) => self.parse_expr_range(min_prec, lhs, limits, op.span)?,
219            };
220
221            if let AssocOp::Range(_) = op.node {
222                break;
223            }
224        }
225
226        Ok((lhs, parsed_something))
227    }
228
229    /// Possibly translate the current token to an associative operator.
230    /// The method does not advance the current token.
231    pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
232        let op = AssocOp::from_token(&self.token);
233
234        // When parsing const expressions, stop parsing when encountering `>`.
235        if self.restrictions.contains(Restrictions::CONST_EXPR)
236            && let Some(op) = op
237            && let AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
238            | AssocOp::AssignOp(AssignOpKind::ShrAssign) = op
239        {
240            return None;
241        }
242
243        // When recovering patterns as expressions, stop parsing when encountering an
244        // assignment `=`, an alternative `|`, or a range `..`.
245        if self.restrictions.contains(Restrictions::IS_PAT)
246            && let Some(op) = op
247            && let AssocOp::Assign
248            | AssocOp::AssignOp(_)
249            | AssocOp::Binary(BinOpKind::BitOr)
250            | AssocOp::Range(_) = op
251        {
252            return None;
253        }
254
255        if let Some(op) = op {
256            return Some(respan(self.token.span, op));
257        }
258
259        self.recover_from_alpha_logic_op()
260    }
261
262    /// Checks if this expression is a successfully parsed statement.
263    fn expr_is_complete(&self, e: &Expr) -> bool {
264        self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
265    }
266
267    /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
268    /// The other two variants are handled in `parse_prefix_range_expr` below.
269    fn parse_expr_range(
270        &mut self,
271        min_prec: Bound<ExprPrecedence>,
272        lhs: Box<Expr>,
273        limits: RangeLimits,
274        cur_op_span: Span,
275    ) -> PResult<'a, Box<Expr>> {
276        let rhs = if self.is_at_start_of_range_notation_rhs() {
277            let maybe_lt = self.token;
278            Some(
279                self.parse_expr_assoc(min_prec)
280                    .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
281            )
282        } else {
283            None
284        };
285        let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
286        let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);
287        let range = self.mk_range(Some(lhs), rhs, limits);
288        Ok(self.mk_expr(span, range))
289    }
290
291    fn is_at_start_of_range_notation_rhs(&self) -> bool {
292        if self.token.can_begin_expr() {
293            // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
294            if self.token == token::OpenBrace {
295                return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
296            }
297            true
298        } else {
299            false
300        }
301    }
302
303    /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
304    fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
305        if !attrs.is_empty() {
306            let err = crate::diagnostics::DotDotRangeAttribute { span: self.token.span };
307            self.dcx().emit_err(err);
308        }
309
310        self.reject_dotdotdot_expr_op();
311
312        if true {
    if !self.token.is_range_separator() {
        {
            ::core::panicking::panic_fmt(format_args!("parse_prefix_range_expr: token {0:?} is not DotDot/DotDotEq",
                    self.token));
        }
    };
};debug_assert!(
313            self.token.is_range_separator(),
314            "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
315            self.token
316        );
317
318        let limits = match self.token.kind {
319            token::DotDot => RangeLimits::HalfOpen,
320            _ => RangeLimits::Closed,
321        };
322        let op = AssocOp::from_token(&self.token);
323        self.collect_tokens_for_expr(AttrWrapper::empty(), |this, _empty_attrs| {
324            let lo = this.token.span;
325            let maybe_lt = this.look_ahead(1, |t| t.clone());
326            this.bump();
327            let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
328                // RHS must be parsed with more associativity than the dots.
329                this.parse_expr_assoc(Bound::Excluded(op.unwrap().precedence()))
330                    .map(|expr| (lo.to(expr.span), Some(expr)))
331                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
332            } else {
333                (lo, None)
334            };
335            let range = this.mk_range(None, opt_end, limits);
336            Ok(this.mk_expr(span, range))
337        })
338    }
339
340    /// Parses a prefix-unary-operator expr.
341    fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
342        let lo = self.token.span;
343
344        macro_rules! make_it {
345            ($this:ident, $attrs:expr, |this, _| $body:expr) => {
346                $this.collect_tokens_for_expr($attrs, |$this, attrs| {
347                    let (hi, ex) = $body?;
348                    Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
349                })
350            };
351        }
352
353        let this = self;
354
355        // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
356        match this.token.uninterpolate().kind {
357            // `!expr`
358            token::Bang => this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.parse_expr_unary(lo, UnOp::Not)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)),
359            // `~expr`
360            token::Tilde => this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.recover_tilde_expr(lo)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
361            // `-expr`
362            token::Minus => {
363                this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.parse_expr_unary(lo, UnOp::Neg)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg))
364            }
365            // `*expr`
366            token::Star => {
367                this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.parse_expr_unary(lo, UnOp::Deref)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref))
368            }
369            // `&expr` and `&&expr`
370            token::And | token::AndAnd => {
371                this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.parse_expr_borrow(lo)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo))
372            }
373            // `+lit`
374            token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
375                let mut err = crate::diagnostics::LeadingPlusNotSupported {
376                    span: lo,
377                    remove_plus: None,
378                    add_parentheses: None,
379                };
380
381                // a block on the LHS might have been intended to be an expression instead
382                if let Some(sp) =
383                    this.psess.complete_stmt_exprs_before_bin_op_lookalike.borrow().get(&lo)
384                {
385                    err.add_parentheses =
386                        Some(crate::diagnostics::ExprParenthesesNeeded::surrounding(*sp));
387                } else {
388                    err.remove_plus = Some(lo);
389                }
390                this.dcx().emit_err(err);
391
392                this.bump(); // `+`
393                Ok(this.parse_expr_prefix_common(lo)?.1)
394            }
395            // Recover from `++x`:
396            token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
397                let starts_stmt =
398                    this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
399                let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
400                // Eat both `+`s.
401                this.bump();
402                this.bump();
403
404                let operand = this.parse_expr_dot_or_call(attrs)?;
405                return Err(this.report_inc_dec_op(
406                    &operand,
407                    starts_stmt,
408                    diagnostics::IncOrDec::Inc,
409                    diagnostics::UnaryFixity::Pre,
410                    pre_span,
411                ));
412            }
413            token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
414                this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.recover_not_expr(lo)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
415            }
416            _ => this.parse_expr_dot_or_call(attrs),
417        }
418    }
419
420    fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {
421        let attrs = self.parse_outer_attributes()?;
422        let expr = if self.token.is_range_separator() {
423            self.parse_expr_prefix_range(attrs)
424        } else {
425            self.parse_expr_prefix(attrs)
426        }?;
427        let span = self.interpolated_or_expr_span(&expr);
428        Ok((lo.to(span), expr))
429    }
430
431    fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
432        self.bump(); // `op`
433        let (span, expr) = self.parse_expr_prefix_common(lo)?;
434        Ok((span, self.mk_unary(op, expr)))
435    }
436
437    /// Recover on `~expr` in favor of `!expr`.
438    fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
439        self.dcx().emit_err(crate::diagnostics::TildeAsUnaryOperator(lo));
440
441        self.parse_expr_unary(lo, UnOp::Not)
442    }
443
444    fn is_mistaken_not_ident_negation(&self) -> bool {
445        let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
446            // These tokens can start an expression after `!`, but
447            // can't continue an expression after an ident
448            token::Ident(name, kind) => token::ident_can_begin_expr(name, t.span, kind),
449            token::Literal(..) | token::Pound => true,
450            _ => t.is_metavar_expr(),
451        };
452        self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
453    }
454
455    /// Recover on `not expr` in favor of `!expr`.
456    fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
457        let negated_token = self.look_ahead(1, |t| *t);
458
459        let sub_diag = if negated_token.is_numeric_lit() {
460            crate::diagnostics::NotAsNegationOperatorSub::SuggestNotBitwise
461        } else if negated_token.is_bool_lit() {
462            crate::diagnostics::NotAsNegationOperatorSub::SuggestNotLogical
463        } else {
464            crate::diagnostics::NotAsNegationOperatorSub::SuggestNotDefault
465        };
466
467        self.dcx().emit_err(crate::diagnostics::NotAsNegationOperator {
468            negated: negated_token.span,
469            negated_desc: super::token_descr(&negated_token),
470            // Span the `not` plus trailing whitespace to avoid
471            // trailing whitespace after the `!` in our suggestion
472            sub: sub_diag(
473                self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
474            ),
475        });
476
477        self.parse_expr_unary(lo, UnOp::Not)
478    }
479
480    /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
481    fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
482        match self.prev_token.kind {
483            token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
484            token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
485                // `expr.span` is the interpolated span, because invisible open
486                // and close delims both get marked with the same span, one
487                // that covers the entire thing between them. (See
488                // `rustc_expand::mbe::transcribe::transcribe`.)
489                self.prev_token.span
490            }
491            _ => expr.span,
492        }
493    }
494
495    fn parse_assoc_op_cast(
496        &mut self,
497        lhs: Box<Expr>,
498        lhs_span: Span,
499        op_span: Span,
500    ) -> PResult<'a, Box<Expr>> {
501        let mk_expr = |this: &mut Self, rhs: Box<Ty>| {
502            let span = this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
503            this.mk_expr(span, ExprKind::Cast(lhs, rhs))
504        };
505
506        // Save the state of the parser before parsing type normally, in case there is a
507        // LessThan comparison after this cast.
508        let parser_snapshot_before_type = self.clone();
509        let cast_expr = match self.parse_as_cast_ty() {
510            Ok(rhs) => mk_expr(self, rhs),
511            Err(type_err) => {
512                if !self.may_recover() {
513                    return Err(type_err);
514                }
515
516                // Rewind to before attempting to parse the type with generics, to recover
517                // from situations like `x as usize < y` in which we first tried to parse
518                // `usize < y` as a type with generic arguments.
519                let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
520
521                match self.parse_path(PathStyle::Expr) {
522                    Ok(path) => {
523                        let span_after_type = parser_snapshot_after_type.token.span;
524                        let expr =
525                            mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path.clone())));
526
527                        let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
528                        match self.token.kind {
529                            token::Lt => self.dcx().emit_err(
530                                crate::diagnostics::ComparisonInterpretedAsGeneric {
531                                    comparison: self.token.span,
532                                    r#type: pprust::path_to_string(&path),
533                                    args: args_span,
534                                    suggestion:
535                                        crate::diagnostics::ComparisonInterpretedAsGenericSugg {
536                                            left: expr.span.shrink_to_lo(),
537                                            right: expr.span.shrink_to_hi(),
538                                        },
539                                },
540                            ),
541                            token::Shl => {
542                                self.dcx().emit_err(crate::diagnostics::ShiftInterpretedAsGeneric {
543                                    shift: self.token.span,
544                                    r#type: pprust::path_to_string(&path),
545                                    args: args_span,
546                                    suggestion: crate::diagnostics::ShiftInterpretedAsGenericSugg {
547                                        left: expr.span.shrink_to_lo(),
548                                        right: expr.span.shrink_to_hi(),
549                                    },
550                                })
551                            }
552                            _ => {
553                                // We can end up here even without `<` being the next token, for
554                                // example because `parse_ty_no_plus` returns `Err` on keywords,
555                                // but `parse_path` returns `Ok` on them due to error recovery.
556                                // Return original error and parser state.
557                                *self = parser_snapshot_after_type;
558                                return Err(type_err);
559                            }
560                        };
561
562                        // Successfully parsed the type path leaving a `<` yet to parse.
563                        type_err.cancel();
564
565                        // Keep `x as usize` as an expression in AST and continue parsing.
566                        expr
567                    }
568                    Err(path_err) => {
569                        // Couldn't parse as a path, return original error and parser state.
570                        path_err.cancel();
571                        *self = parser_snapshot_after_type;
572                        return Err(type_err);
573                    }
574                }
575            }
576        };
577
578        // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
579        // after a cast. If one is present, emit an error then return a valid
580        // parse tree; For something like `&x as T[0]` will be as if it was
581        // written `((&x) as T)[0]`.
582
583        let span = cast_expr.span;
584        let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
585
586        // Check if an illegal postfix operator has been added after the cast.
587        // If the resulting expression is not a cast, it is an illegal postfix operator.
588        if !#[allow(non_exhaustive_omitted_patterns)] match with_postfix.kind {
    ExprKind::Cast(_, _) => true,
    _ => false,
}matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
589            let kind = match with_postfix.kind {
590                ExprKind::Index(..) => "indexing",
591                ExprKind::Try(_) => "`?`",
592                ExprKind::Field(_, _) => "a field access",
593                ExprKind::MethodCall(_) => "a method call",
594                ExprKind::Call(_, _) => "a function call",
595                ExprKind::Await(_, _) => "`.await`",
596                ExprKind::Use(_, _) => "`.use`",
597                ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
598                ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
599                ExprKind::Err(_) => return Ok(with_postfix),
600                _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("did not expect {0:?} as an illegal postfix operator following cast",
                with_postfix.kind)));
}unreachable!(
601                    "did not expect {:?} as an illegal postfix operator following cast",
602                    with_postfix.kind
603                ),
604            };
605            self.dcx()
606                .struct_span_err(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cast cannot be followed by {0}",
                kind))
    })format!("cast cannot be followed by {kind}"))
607                .with_multipart_suggestion(
608                    "try surrounding the expression in parentheses",
609                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span.shrink_to_lo(), "(".to_string()),
                (span.shrink_to_hi(), ")".to_string())]))vec![
610                        (span.shrink_to_lo(), "(".to_string()),
611                        (span.shrink_to_hi(), ")".to_string()),
612                    ],
613                    Applicability::MachineApplicable,
614                )
615                .emit();
616        };
617        Ok(with_postfix)
618    }
619
620    /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
621    fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
622        self.expect_and()?;
623        let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
624        let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.
625        let (borrow_kind, mutbl) = self.parse_borrow_modifiers();
626        let (span, expr) = self.parse_expr_prefix_common(lo)?;
627        if let Some(lt) = lifetime {
628            self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
629        }
630
631        // Add expected tokens if we parsed `&raw` as an expression.
632        // This will make sure we see "expected `const`, `mut`", and
633        // guides recovery in case we write `&raw expr`.
634        if borrow_kind == ast::BorrowKind::Ref
635            && mutbl == ast::Mutability::Not
636            && #[allow(non_exhaustive_omitted_patterns)] match &expr.kind {
    ExprKind::Path(None, p) if *p == kw::Raw => true,
    _ => false,
}matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw)
637        {
638            self.expected_token_types.insert(TokenType::KwMut);
639            self.expected_token_types.insert(TokenType::KwConst);
640        }
641
642        Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
643    }
644
645    fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
646        self.dcx().emit_err(crate::diagnostics::LifetimeInBorrowExpression {
647            span,
648            lifetime_span: lt_span,
649        });
650    }
651
652    /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
653    fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
654        if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Raw,
    token_type: crate::parser::token_type::TokenType::KwRaw,
}exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
655            // `raw [ const | mut ]`.
656            let found_raw = self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Raw,
    token_type: crate::parser::token_type::TokenType::KwRaw,
}exp!(Raw));
657            if !found_raw { ::core::panicking::panic("assertion failed: found_raw") };assert!(found_raw);
658            let mutability = self.parse_mut_or_const().unwrap();
659            (ast::BorrowKind::Raw, mutability)
660        } else {
661            match self.parse_pin_and_mut() {
662                // `mut?`
663                (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),
664                // `pin [ const | mut ]`.
665                // `pin` has been gated in `self.parse_pin_and_mut()` so we don't
666                // need to gate it here.
667                (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),
668            }
669        }
670    }
671
672    /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
673    fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
674        self.collect_tokens_for_expr(attrs, |this, attrs| {
675            let base = this.parse_expr_bottom()?;
676            let span = this.interpolated_or_expr_span(&base);
677            this.parse_expr_dot_or_call_with(attrs, base, span)
678        })
679    }
680
681    pub(super) fn parse_expr_dot_or_call_with(
682        &mut self,
683        mut attrs: ast::AttrVec,
684        mut e: Box<Expr>,
685        lo: Span,
686    ) -> PResult<'a, Box<Expr>> {
687        let mut res = loop {
688            let has_question = if self.prev_token.is_keyword(kw::Return) {
689                // We are using noexpect here because we don't expect a `?` directly after
690                // a `return` which could be suggested otherwise.
691                self.eat_noexpect(&token::Question)
692            } else {
693                self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Question,
    token_type: crate::parser::token_type::TokenType::Question,
}exp!(Question))
694            };
695            if has_question {
696                // `expr?`
697                e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
698                continue;
699            }
700            let has_dot = if self.prev_token.is_keyword(kw::Return) {
701                // We are using noexpect here because we don't expect a `.` directly after
702                // a `return` which could be suggested otherwise.
703                self.eat_noexpect(&token::Dot)
704            } else if self.token == TokenKind::RArrow && self.may_recover() {
705                // Recovery for `expr->suffix`.
706                self.bump();
707                let span = self.prev_token.span;
708                self.dcx().emit_err(crate::diagnostics::ExprRArrowCall { span });
709                true
710            } else {
711                self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Dot,
    token_type: crate::parser::token_type::TokenType::Dot,
}exp!(Dot))
712            };
713            if has_dot {
714                // expr.f
715                e = self.parse_dot_suffix_expr(lo, e)?;
716                continue;
717            }
718            if self.expr_is_complete(&e) {
719                break Ok(e);
720            }
721            e = match self.token.kind {
722                token::OpenParen => self.parse_expr_fn_call(lo, e),
723                token::OpenBracket => self.parse_expr_index(lo, e)?,
724                _ => break Ok(e),
725            }
726        };
727
728        // Stitch the list of outer attributes onto the return value. A little
729        // bit ugly, but the best way given the current code structure.
730        if !attrs.is_empty()
731            && let Ok(expr) = &mut res
732        {
733            mem::swap(&mut expr.attrs, &mut attrs);
734            expr.attrs.extend(attrs)
735        }
736        res
737    }
738
739    pub(super) fn parse_dot_suffix_expr(
740        &mut self,
741        lo: Span,
742        base: Box<Expr>,
743    ) -> PResult<'a, Box<Expr>> {
744        // At this point we've consumed something like `expr.` and `self.token` holds the token
745        // after the dot.
746        match self.token.uninterpolate().kind {
747            token::Ident(..) => self.parse_dot_suffix(base, lo),
748            token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
749                let ident_span = self.token.span;
750                self.bump();
751                Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))
752            }
753            token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
754                Ok(match self.break_up_float(symbol, self.token.span) {
755                    // 1e2
756                    DestructuredFloat::Single(sym, _sp) => {
757                        // `foo.1e2`: a single complete dot access, fully consumed. We end up with
758                        // the `1e2` token in `self.prev_token` and the following token in
759                        // `self.token`.
760                        let ident_span = self.token.span;
761                        self.bump();
762                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
763                    }
764                    // 1.
765                    DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
766                        // `foo.1.`: a single complete dot access and the start of another.
767                        // We end up with the `sym` (`1`) token in `self.prev_token` and a dot in
768                        // `self.token`.
769                        if !suffix.is_none() {
    ::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
770                        self.token = Token::new(token::Ident(sym, IdentKind::Normal), ident_span);
771                        self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
772                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
773                    }
774                    // 1.2 | 1.2e3
775                    DestructuredFloat::MiddleDot(
776                        sym1,
777                        ident1_span,
778                        _dot_span,
779                        sym2,
780                        ident2_span,
781                    ) => {
782                        // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with
783                        // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following
784                        // token in `self.token`.
785                        let next_token2 =
786                            Token::new(token::Ident(sym2, IdentKind::Normal), ident2_span);
787                        self.bump_with((next_token2, self.token_spacing));
788                        self.bump();
789                        let base1 =
790                            self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
791                        self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
792                    }
793                    DestructuredFloat::Error => base,
794                })
795            }
796            _ => {
797                self.error_unexpected_after_dot();
798                Ok(base)
799            }
800        }
801    }
802
803    fn error_unexpected_after_dot(&self) {
804        let actual = super::token_descr(&self.token);
805        let span = self.token.span;
806        let sm = self.psess.source_map();
807        let (span, actual) = match (&self.token.kind, self.subparser_name) {
808            (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
809                (span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", snippet))
    })format!("`{}`", snippet))
810            }
811            (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
812                // No need to report an error. This case will only occur when parsing a pasted
813                // metavariable, and we should have emitted an error when parsing the macro call in
814                // the first place. E.g. in this code:
815                // ```
816                // macro_rules! m { ($e:expr) => { $e }; }
817                //
818                // fn main() {
819                //     let f = 1;
820                //     m!(f.);
821                // }
822                // ```
823                // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't
824                // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`
825                // represent the invisible delimiters).
826                self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");
827                return;
828            }
829            _ => (span, actual),
830        };
831        self.dcx().emit_err(crate::diagnostics::UnexpectedTokenAfterDot { span, actual });
832    }
833
834    /// We need an identifier or integer, but the next token is a float.
835    /// Break the float into components to extract the identifier or integer.
836    ///
837    /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.
838    //
839    // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
840    //  parts unless those parts are processed immediately. `TokenCursor` should either
841    //  support pushing "future tokens" (would be also helpful to `break_and_eat`), or
842    //  we should break everything including floats into more basic proc-macro style
843    //  tokens in the lexer (probably preferable).
844    pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
845        #[derive(#[automatically_derived]impl ::core::fmt::Debug for FloatComponent {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::IdentLike(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "IdentLike", &__self_0),
            Self::Punct(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Punct",
                    &__self_0),
        }
    }
}Debug)]
846        enum FloatComponent {
847            IdentLike(String),
848            Punct(char),
849        }
850        use FloatComponent::*;
851
852        let float_str = float.as_str();
853        let mut components = Vec::new();
854        let mut ident_like = String::new();
855        for c in float_str.chars() {
856            if c == '_' || c.is_ascii_alphanumeric() {
857                ident_like.push(c);
858            } else if #[allow(non_exhaustive_omitted_patterns)] match c {
    '.' | '+' | '-' => true,
    _ => false,
}matches!(c, '.' | '+' | '-') {
859                if !ident_like.is_empty() {
860                    components.push(IdentLike(mem::take(&mut ident_like)));
861                }
862                components.push(Punct(c));
863            } else {
864                {
    ::core::panicking::panic_fmt(format_args!("unexpected character in a float token: {0:?}",
            c));
}panic!("unexpected character in a float token: {c:?}")
865            }
866        }
867        if !ident_like.is_empty() {
868            components.push(IdentLike(ident_like));
869        }
870
871        // With proc macros the span can refer to anything, the source may be too short,
872        // or too long, or non-ASCII. It only makes sense to break our span into components
873        // if its underlying text is identical to our float literal.
874        let can_take_span_apart =
875            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
876
877        match &*components {
878            // 1e2
879            [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span),
880            // 1.
881            [IdentLike(left), Punct('.')] => {
882                let (left_span, dot_span) = if can_take_span_apart() {
883                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
884                    let dot_span = span.with_lo(left_span.hi());
885                    (left_span, dot_span)
886                } else {
887                    (span, span)
888                };
889                let left = Symbol::intern(left);
890                DestructuredFloat::TrailingDot(left, left_span, dot_span)
891            }
892            // 1.2 | 1.2e3
893            [IdentLike(left), Punct('.'), IdentLike(right)] => {
894                let (left_span, dot_span, right_span) = if can_take_span_apart() {
895                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
896                    let dot_span =
897                        span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
898                    let right_span = span.with_lo(dot_span.hi());
899                    (left_span, dot_span, right_span)
900                } else {
901                    (span, span, span)
902                };
903                let left = Symbol::intern(left);
904                let right = Symbol::intern(right);
905                DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
906            }
907            // 1e+ | 1e- (recovered)
908            [IdentLike(_), Punct('+' | '-')] |
909            // 1e+2 | 1e-2
910            [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
911            // 1.2e+ | 1.2e-
912            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
913            // 1.2e+3 | 1.2e-3
914            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
915                // See the FIXME about `TokenCursor` above.
916                self.error_unexpected_after_dot();
917                DestructuredFloat::Error
918            }
919            _ => {
    ::core::panicking::panic_fmt(format_args!("unexpected components in a float token: {0:?}",
            components));
}panic!("unexpected components in a float token: {components:?}"),
920        }
921    }
922
923    /// Parse the field access used in offset_of, matched by `$(e:expr)+`.
924    /// Currently returns a list of idents. However, it should be possible in
925    /// future to also do array indices, which might be arbitrary expressions.
926    pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, ThinVec<Ident>> {
927        let mut fields = ThinVec::new();
928        let mut trailing_dot = None;
929
930        loop {
931            // This is expected to use a metavariable $(args:expr)+, but the builtin syntax
932            // could be called directly. Calling `parse_expr` allows this function to only
933            // consider `Expr`s.
934            let expr = self.parse_expr()?;
935            let mut current = &expr;
936            let start_idx = fields.len();
937            loop {
938                match current.kind {
939                    ExprKind::Field(ref left, right) => {
940                        // Field access is read right-to-left.
941                        fields.insert(start_idx, right);
942                        trailing_dot = None;
943                        current = left;
944                    }
945                    // Parse this both to give helpful error messages and to
946                    // verify it can be done with this parser setup.
947                    ExprKind::Index(ref left, ref _right, span) => {
948                        self.dcx().emit_err(crate::diagnostics::ArrayIndexInOffsetOf(span));
949                        current = left;
950                    }
951                    ExprKind::Lit(token::Lit {
952                        kind: token::Float | token::Integer,
953                        symbol,
954                        suffix,
955                    }) => {
956                        if let Some(suffix) = suffix {
957                            self.dcx().emit_err(
958                                crate::diagnostics::InvalidLiteralSuffixOnTupleIndex {
959                                    span: current.span,
960                                    suffix,
961                                },
962                            );
963                        }
964                        match self.break_up_float(symbol, current.span) {
965                            // 1e2
966                            DestructuredFloat::Single(sym, sp) => {
967                                trailing_dot = None;
968                                fields.insert(start_idx, Ident::new(sym, sp));
969                            }
970                            // 1.
971                            DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
972                                if !suffix.is_none() {
    ::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
973                                trailing_dot = Some(dot_span);
974                                fields.insert(start_idx, Ident::new(sym, sym_span));
975                            }
976                            // 1.2 | 1.2e3
977                            DestructuredFloat::MiddleDot(
978                                symbol1,
979                                span1,
980                                _dot_span,
981                                symbol2,
982                                span2,
983                            ) => {
984                                trailing_dot = None;
985                                fields.insert(start_idx, Ident::new(symbol2, span2));
986                                fields.insert(start_idx, Ident::new(symbol1, span1));
987                            }
988                            DestructuredFloat::Error => {
989                                trailing_dot = None;
990                                fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
991                            }
992                        }
993                        break;
994                    }
995                    ExprKind::Path(None, Path { ref segments, .. }) => {
996                        match &segments[..] {
997                            [PathSegment { ident, args: None, .. }] => {
998                                trailing_dot = None;
999                                fields.insert(start_idx, *ident)
1000                            }
1001                            _ => {
1002                                self.dcx()
1003                                    .emit_err(crate::diagnostics::InvalidOffsetOf(current.span));
1004                                break;
1005                            }
1006                        }
1007                        break;
1008                    }
1009                    _ => {
1010                        self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(current.span));
1011                        break;
1012                    }
1013                }
1014            }
1015
1016            if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
1017                break;
1018            } else if trailing_dot.is_none() {
1019                // This loop should only repeat if there is a trailing dot.
1020                self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(self.token.span));
1021                break;
1022            }
1023        }
1024        if let Some(dot) = trailing_dot {
1025            self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(dot));
1026        }
1027        Ok(fields.into_iter().collect())
1028    }
1029
1030    fn mk_expr_tuple_field_access(
1031        &self,
1032        lo: Span,
1033        ident_span: Span,
1034        base: Box<Expr>,
1035        field: Symbol,
1036        suffix: Option<Symbol>,
1037    ) -> Box<Expr> {
1038        if let Some(suffix) = suffix {
1039            self.dcx().emit_err(crate::diagnostics::InvalidLiteralSuffixOnTupleIndex {
1040                span: ident_span,
1041                suffix,
1042            });
1043        }
1044        self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
1045    }
1046
1047    /// Parse a function call expression, `expr(...)`.
1048    fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {
1049        let snapshot = if self.token == token::OpenParen {
1050            Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
1051        } else {
1052            None
1053        };
1054        let open_paren = self.token.span;
1055        let call_depth = self.token_cursor.depth();
1056
1057        let seq = match self.parse_expr_paren_seq() {
1058            Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),
1059            Err(err)
1060                if self.is_expected_raw_ref_mut() && self.token_cursor.depth() == call_depth =>
1061            {
1062                let guar = err.emit_err();
1063                // Preserve the call expression so later passes can still diagnose the callee,
1064                // while treating the malformed `&raw <expr>` argument as an error expression.
1065                let args = self.recover_raw_ref_call_args(guar);
1066                return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));
1067            }
1068            Err(err) => Err(err),
1069        };
1070        match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
1071            Ok(expr) => expr,
1072            Err(err) => self.recover_seq_parse_error(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen), crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen), lo, err),
1073        }
1074    }
1075
1076    fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {
1077        let err_span = self.prev_token.span.to(self.token.span);
1078        let mut args = {
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(self.mk_expr_err(err_span, guar));
    vec
}thin_vec![self.mk_expr_err(err_span, guar)];
1079        while !self.token.kind.is_close_delim_or_eof() {
1080            if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1081                if !self.token.kind.is_close_delim_or_eof() {
1082                    args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));
1083                }
1084            } else {
1085                self.parse_token_tree();
1086            }
1087        }
1088        let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen));
1089        args
1090    }
1091
1092    /// If we encounter a parser state that looks like the user has written a `struct` literal with
1093    /// parentheses instead of braces, recover the parser state and provide suggestions.
1094    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("maybe_recover_struct_lit_bad_delims",
                                    "rustc_parse::parser::expr", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/bbcdfd90a3f81ca2a5f6d69b943a6ff0d8582102/compiler/rustc_parse/src/parser/expr.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1094u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_parse::parser::expr"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("lo")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("lo");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("open_paren")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("open_paren");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lo)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&open_paren)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: PResult<'a, Box<Expr>> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            match (self.may_recover(), seq, snapshot) {
                (true, Err(err),
                    Some((mut snapshot, ExprKind::Path(None, path)))) => {
                    snapshot.bump();
                    match snapshot.parse_struct_fields(path.clone(), false,
                            crate::parser::token_type::ExpTokenPair {
                                tok: rustc_ast::token::CloseParen,
                                token_type: crate::parser::token_type::TokenType::CloseParen,
                            }) {
                        Ok((fields, ..)) if
                            snapshot.eat(crate::parser::token_type::ExpTokenPair {
                                    tok: rustc_ast::token::CloseParen,
                                    token_type: crate::parser::token_type::TokenType::CloseParen,
                                }) => {
                            self.restore_snapshot(snapshot);
                            let close_paren = self.prev_token.span;
                            let span = lo.to(close_paren);
                            let fields: Vec<_> =
                                fields.into_iter().filter(|field|
                                            !field.is_shorthand).collect();
                            let guar =
                                if !fields.is_empty() &&
                                        self.span_to_snippet(close_paren).is_ok_and(|snippet|
                                                snippet == ")") {
                                    err.cancel();
                                    let type_str = pprust::path_to_string(&path);
                                    self.dcx().emit_err(crate::diagnostics::ParenthesesWithStructFields {
                                            span,
                                            braces_for_struct: crate::diagnostics::BracesForStructLiteral {
                                                first: open_paren,
                                                second: close_paren,
                                                r#type: type_str.clone(),
                                            },
                                            no_fields_for_fn: crate::diagnostics::NoFieldsForFnCall {
                                                r#type: type_str,
                                                fields: fields.into_iter().map(|field|
                                                            field.span.until(field.expr.span)).collect(),
                                            },
                                        })
                                } else { err.emit_err() };
                            Ok(self.mk_expr_err(span, guar))
                        }
                        Ok(_) => Err(err),
                        Err(err2) => { err2.cancel(); Err(err) }
                    }
                }
                (_, seq, _) => seq,
            }
        }
    }
}#[instrument(skip(self, seq, snapshot), level = "trace")]
1095    fn maybe_recover_struct_lit_bad_delims(
1096        &mut self,
1097        lo: Span,
1098        open_paren: Span,
1099        seq: PResult<'a, Box<Expr>>,
1100        snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
1101    ) -> PResult<'a, Box<Expr>> {
1102        match (self.may_recover(), seq, snapshot) {
1103            (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
1104                snapshot.bump(); // `(`
1105                match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
1106                    Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
1107                        // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
1108                        // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
1109                        self.restore_snapshot(snapshot);
1110                        let close_paren = self.prev_token.span;
1111                        let span = lo.to(close_paren);
1112                        // filter shorthand fields
1113                        let fields: Vec<_> =
1114                            fields.into_iter().filter(|field| !field.is_shorthand).collect();
1115
1116                        let guar = if !fields.is_empty() &&
1117                            // `token.kind` should not be compared here.
1118                            // This is because the `snapshot.token.kind` is treated as the same as
1119                            // that of the open delim in `TokenTreesReader::parse_token_tree`, even
1120                            // if they are different.
1121                            self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
1122                        {
1123                            err.cancel();
1124                            let type_str = pprust::path_to_string(&path);
1125                            self.dcx().emit_err(crate::diagnostics::ParenthesesWithStructFields {
1126                                span,
1127                                braces_for_struct: crate::diagnostics::BracesForStructLiteral {
1128                                    first: open_paren,
1129                                    second: close_paren,
1130                                    r#type: type_str.clone(),
1131                                },
1132                                no_fields_for_fn: crate::diagnostics::NoFieldsForFnCall {
1133                                    r#type: type_str,
1134                                    fields: fields
1135                                        .into_iter()
1136                                        .map(|field| field.span.until(field.expr.span))
1137                                        .collect(),
1138                                },
1139                            })
1140                        } else {
1141                            err.emit_err()
1142                        };
1143                        Ok(self.mk_expr_err(span, guar))
1144                    }
1145                    Ok(_) => Err(err),
1146                    Err(err2) => {
1147                        err2.cancel();
1148                        Err(err)
1149                    }
1150                }
1151            }
1152            (_, seq, _) => seq,
1153        }
1154    }
1155
1156    /// Parse an indexing expression `expr[...]`.
1157    fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {
1158        let prev_token = self.prev_token;
1159        let open_delim_span = self.token.span;
1160        self.bump(); // `[`
1161        let index = self.parse_expr()?;
1162        self.recover_from_missing_semicolon_before_array(prev_token.span, open_delim_span)?;
1163        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBracket,
    token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket)).map_err(|mut err| {
1164            if prev_token.is_non_reserved_ident() {
1165                err.span_suggestion_verbose(
1166                    prev_token.span.shrink_to_hi(),
1167                    "you might have meant to call a macro",
1168                    "!".to_string(),
1169                    Applicability::MaybeIncorrect,
1170                );
1171            }
1172            err
1173        })?;
1174        Ok(self.mk_expr(
1175            lo.to(self.prev_token.span),
1176            self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
1177        ))
1178    }
1179
1180    /// Assuming we have just parsed `.`, continue parsing into an expression.
1181    fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {
1182        if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Await,
    token_type: crate::parser::token_type::TokenType::KwAwait,
}exp!(Await)) {
1183            return Ok(self.mk_await_expr(self_arg, lo));
1184        }
1185
1186        if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Use,
    token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use)) {
1187            let use_span = self.prev_token.span;
1188            self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
1189            return Ok(self.mk_use_expr(self_arg, lo));
1190        }
1191
1192        // Post-fix match
1193        if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Match,
    token_type: crate::parser::token_type::TokenType::KwMatch,
}exp!(Match)) {
1194            let match_span = self.prev_token.span;
1195            self.psess.gated_spans.gate(sym::postfix_match, match_span);
1196            return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1197        }
1198
1199        // Parse a postfix `yield`.
1200        if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Yield,
    token_type: crate::parser::token_type::TokenType::KwYield,
}exp!(Yield)) {
1201            let yield_span = self.prev_token.span;
1202            self.psess.gated_spans.gate(sym::yield_expr, yield_span);
1203            return Ok(
1204                self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
1205            );
1206        }
1207
1208        let fn_span_lo = self.token.span;
1209        let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
1210        self.check_trailing_angle_brackets(&seg, &[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)]);
1211        self.check_turbofish_missing_angle_brackets(&mut seg);
1212
1213        if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1214            // Method call `expr.f()`
1215            let args = self.parse_expr_paren_seq()?;
1216            let fn_span = fn_span_lo.to(self.prev_token.span);
1217            let span = lo.to(self.prev_token.span);
1218            Ok(self.mk_expr(
1219                span,
1220                ExprKind::MethodCall(Box::new(ast::MethodCall {
1221                    seg,
1222                    receiver: self_arg,
1223                    args,
1224                    span: fn_span,
1225                })),
1226            ))
1227        } else {
1228            // Field access `expr.f`
1229            let span = lo.to(self.prev_token.span);
1230            if let Some(args) = seg.args {
1231                // See `StashKey::GenericInFieldExpr` for more info on why we stash this.
1232                self.dcx()
1233                    .create_err(crate::diagnostics::FieldExpressionWithGeneric(args.span()))
1234                    .stash(seg.ident.span, StashKey::GenericInFieldExpr);
1235            }
1236
1237            Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
1238        }
1239    }
1240
1241    /// At the bottom (top?) of the precedence hierarchy,
1242    /// Parses things like parenthesized exprs, macros, `return`, etc.
1243    ///
1244    /// N.B., this does not parse outer attributes, and is private because it only works
1245    /// correctly if called from `parse_expr_dot_or_call`.
1246    fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {
1247        if true && self.may_recover() &&
                let Some(mv_kind) = self.token.is_metavar_seq() &&
            let token::MetaVarKind::Ty { .. } = mv_kind &&
        self.check_noexpect_past_close_delim(&token::PathSep) {
    let ty =
        self.eat_metavar_seq(mv_kind,
                |this|
                    this.parse_ty_no_question_mark_recover()).expect("metavar seq ty");
    return self.maybe_recover_from_bad_qpath_stage_2(self.prev_token.span,
            ty);
};maybe_recover_from_interpolated_ty_qpath!(self, true);
1248
1249        let span = self.token.span;
1250        if let Some(expr) = self.eat_metavar_seq_with_matcher(
1251            |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
    MetaVarKind::Expr { .. } => true,
    _ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
1252            |this| {
1253                // Force collection (as opposed to just `parse_expr`) is required to avoid the
1254                // attribute duplication seen in #138478.
1255                let expr = this.parse_expr_force_collect();
1256                // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly
1257                // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line
1258                // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in
1259                // `compiler/rustc_index/src/bit_set/tests.rs`.
1260                if this.token.kind == token::Comma {
1261                    this.bump();
1262                }
1263                expr
1264            },
1265        ) {
1266            return Ok(expr);
1267        } else if let Some(lit) =
1268            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
1269        {
1270            return Ok(lit);
1271        } else if let Some(block) =
1272            self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
1273        {
1274            return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
1275        } else if let Some(path) =
1276            self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
1277        {
1278            return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
1279        }
1280
1281        // Outer attributes are already parsed and will be
1282        // added to the return value after the fact.
1283
1284        let restrictions = self.restrictions;
1285        self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
1286            // Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.
1287            let lo = this.token.span;
1288            if let token::Literal(_) = this.token.kind {
1289                // This match arm is a special-case of the `_` match arm below and
1290                // could be removed without changing functionality, but it's faster
1291                // to have it here, especially for programs with large constants.
1292                this.parse_expr_lit()
1293            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1294                this.parse_expr_tuple_parens(restrictions)
1295            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
1296                if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1297                    return Ok(expr);
1298                }
1299                if let Some(arr) = this.recover_from_c_array(lo) {
1300                    return Ok(arr);
1301                }
1302                this.parse_expr_block(None, lo, BlockCheckMode::Default)
1303            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Or,
    token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)) || this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OrOr,
    token_type: crate::parser::token_type::TokenType::OrOr,
}exp!(OrOr)) {
1304                this.parse_expr_closure().map_err(|mut err| {
1305                    // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
1306                    // then suggest parens around the lhs.
1307                    if let Some(sp) =
1308                        this.psess.complete_stmt_exprs_before_bin_op_lookalike.borrow().get(&lo)
1309                    {
1310                        err.subdiagnostic(crate::diagnostics::ExprParenthesesNeeded::surrounding(
1311                            *sp,
1312                        ));
1313                    }
1314                    err
1315                })
1316            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBracket,
    token_type: crate::parser::token_type::TokenType::OpenBracket,
}exp!(OpenBracket)) {
1317                this.parse_expr_array_or_repeat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBracket,
    token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket))
1318            } else if this.check_path() {
1319                this.parse_expr_path_start()
1320            } else if this.token.is_keyword(kw::Move)
1321                && this.look_ahead(1, |t| *t == token::OpenParen)
1322            {
1323                this.parse_expr_move()
1324            } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Move,
    token_type: crate::parser::token_type::TokenType::KwMove,
}exp!(Move))
1325                || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Use,
    token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use))
1326                || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Static,
    token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static))
1327                || this.check_const_closure()
1328            {
1329                this.parse_expr_closure()
1330            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::If,
    token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If)) {
1331                this.parse_expr_if()
1332            } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::For,
    token_type: crate::parser::token_type::TokenType::KwFor,
}exp!(For)) {
1333                if this.choose_generics_over_qpath(1) {
1334                    this.parse_expr_closure()
1335                } else {
1336                    if !this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
                kw: rustc_span::symbol::kw::For,
                token_type: crate::parser::token_type::TokenType::KwFor,
            }) {
    ::core::panicking::panic("assertion failed: this.eat_keyword(exp!(For))")
};assert!(this.eat_keyword(exp!(For)));
1337                    this.parse_expr_for(None, lo)
1338                }
1339            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::While,
    token_type: crate::parser::token_type::TokenType::KwWhile,
}exp!(While)) {
1340                this.parse_expr_while(None, lo)
1341            } else if let Some(label) = this.eat_label() {
1342                this.parse_expr_labeled(label, true)
1343            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Loop,
    token_type: crate::parser::token_type::TokenType::KwLoop,
}exp!(Loop)) {
1344                this.parse_expr_loop(None, lo).map_err(|mut err| {
1345                    err.span_label(lo, "while parsing this `loop` expression");
1346                    err
1347                })
1348            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Match,
    token_type: crate::parser::token_type::TokenType::KwMatch,
}exp!(Match)) {
1349                this.parse_expr_match().map_err(|mut err| {
1350                    err.span_label(lo, "while parsing this `match` expression");
1351                    err
1352                })
1353            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Unsafe,
    token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe)) {
1354                this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
1355                    |mut err| {
1356                        err.span_label(lo, "while parsing this `unsafe` expression");
1357                        err
1358                    },
1359                )
1360            } else if this.check_inline_const(0) {
1361                this.parse_const_block(lo, false)
1362            } else if this.may_recover() && this.is_do_catch_block() {
1363                this.recover_do_catch()
1364            } else if this.is_try_block() {
1365                this.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Try,
    token_type: crate::parser::token_type::TokenType::KwTry,
}exp!(Try))?;
1366                this.parse_try_block(lo)
1367            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Return,
    token_type: crate::parser::token_type::TokenType::KwReturn,
}exp!(Return)) {
1368                this.parse_expr_return()
1369            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Continue,
    token_type: crate::parser::token_type::TokenType::KwContinue,
}exp!(Continue)) {
1370                this.parse_expr_continue(lo)
1371            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Break,
    token_type: crate::parser::token_type::TokenType::KwBreak,
}exp!(Break)) {
1372                this.parse_expr_break()
1373            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Yield,
    token_type: crate::parser::token_type::TokenType::KwYield,
}exp!(Yield)) {
1374                this.parse_expr_yield()
1375            } else if this.is_do_yeet() {
1376                this.parse_expr_yeet()
1377            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Become,
    token_type: crate::parser::token_type::TokenType::KwBecome,
}exp!(Become)) {
1378                this.parse_expr_become()
1379            } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Let,
    token_type: crate::parser::token_type::TokenType::KwLet,
}exp!(Let)) {
1380                this.parse_expr_let(restrictions)
1381            } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Underscore,
    token_type: crate::parser::token_type::TokenType::KwUnderscore,
}exp!(Underscore)) {
1382                if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1383                    return Ok(expr);
1384                }
1385                Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
1386            } else if this.eat_forced_keyword_noexpect(kw::OffsetOf) {
1387                this.parse_expr_offset_of(lo)
1388            } else if this.eat_forced_keyword_noexpect(kw::TypeAscribe) {
1389                this.parse_expr_type_ascribe(lo)
1390            } else if this.eat_forced_keyword_noexpect(kw::WrapBinder) {
1391                this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)
1392            } else if this.eat_forced_keyword_noexpect(kw::UnwrapBinder) {
1393                this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)
1394            } else if this.token_uninterpolated_span().at_least_rust_2018() {
1395                // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
1396                let at_async = this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Async,
    token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async));
1397                // check for `gen {}` and `gen move {}`
1398                // or `async gen {}` and `async gen move {}`
1399                // FIXME: (async) gen closures aren't yet parsed.
1400                // FIXME(gen_blocks): Parse `gen async` and suggest swap
1401                // FIXME(forced_keywords): Allow k#gen blocks prior to Rust 2024, too!
1402                if this.token_uninterpolated_span().at_least_rust_2024()
1403                    && this.is_gen_block(kw::Gen, at_async as usize)
1404                {
1405                    this.parse_gen_block()
1406                // Check for `async {` and `async move {`,
1407                } else if this.is_gen_block(kw::Async, 0) {
1408                    this.parse_gen_block()
1409                } else if at_async {
1410                    this.parse_expr_closure()
1411                } else if this.eat_keyword_noexpect(kw::Await) {
1412                    this.recover_incorrect_await_syntax(lo)
1413                } else {
1414                    this.parse_expr_lit()
1415                }
1416            } else {
1417                this.parse_expr_lit()
1418            }
1419        })
1420    }
1421
1422    fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {
1423        let lo = self.token.span;
1424        match self.parse_opt_token_lit() {
1425            Some((token_lit, _)) => {
1426                let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));
1427                self.maybe_recover_from_bad_qpath(expr)
1428            }
1429            None => self.try_macro_suggestion(),
1430        }
1431    }
1432
1433    fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
1434        let lo = self.token.span;
1435        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1436        let (es, trailing_comma) = match self.parse_seq_to_end(
1437            crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1438            SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
1439            |p| p.parse_expr_res(restrictions.intersection(Restrictions::ALLOW_LET)),
1440        ) {
1441            Ok(x) => x,
1442            Err(err) if self.may_recover() => {
1443                return Ok(self.recover_seq_parse_error(
1444                    crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen),
1445                    crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1446                    lo,
1447                    err,
1448                ));
1449            }
1450            Err(err) => return Err(err),
1451        };
1452        let kind = if es.len() == 1 && #[allow(non_exhaustive_omitted_patterns)] match trailing_comma {
    Trailing::No => true,
    _ => false,
}matches!(trailing_comma, Trailing::No) {
1453            // `(e)` is parenthesized `e`.
1454            ExprKind::Paren(es.into_iter().next().unwrap())
1455        } else {
1456            // `(e,)` is a tuple with only one field, `e`.
1457            ExprKind::Tup(es)
1458        };
1459        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1460        self.maybe_recover_from_bad_qpath(expr)
1461    }
1462
1463    fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {
1464        let lo = self.token.span;
1465        self.bump(); // `[` or other open delim
1466
1467        let kind = if self.eat(close) {
1468            // Empty vector
1469            ExprKind::Array(ThinVec::new())
1470        } else {
1471            // Non-empty vector
1472            let first_expr = self.parse_expr()?;
1473            if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Semi,
    token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
1474                // Repeating array syntax: `[ 0; 512 ]`
1475                let count = self.parse_expr_anon_const()?;
1476                self.expect(close)?;
1477                ExprKind::Repeat(first_expr, count)
1478            } else if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1479                // Vector with two or more elements.
1480                let sep = SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
1481                let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
1482                exprs.insert(0, first_expr);
1483                ExprKind::Array(exprs)
1484            } else {
1485                // Vector with one element
1486                self.expect(close)?;
1487                ExprKind::Array({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(first_expr);
    vec
}thin_vec![first_expr])
1488            }
1489        };
1490        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1491        self.maybe_recover_from_bad_qpath(expr)
1492    }
1493
1494    fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {
1495        let maybe_eq_tok = self.prev_token;
1496        let (qself, path) = if self.eat_lt() {
1497            let lt_span = self.prev_token.span;
1498            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
1499                // Suggests using '<=' if there is an error parsing qpath when the previous token
1500                // is an '=' token. Only emits suggestion if the '<' token and '=' token are
1501                // directly adjacent (i.e. '=<')
1502                if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
1503                    let eq_lt = maybe_eq_tok.span.to(lt_span);
1504                    err.span_suggestion_verbose(
1505                        eq_lt,
1506                        "you might have meant to write a \"less than or equal to\" comparison",
1507                        "<=",
1508                        Applicability::Unspecified,
1509                    );
1510                }
1511                err
1512            })?;
1513            (Some(qself), path)
1514        } else {
1515            (None, self.parse_path(PathStyle::Expr)?)
1516        };
1517
1518        // `!`, as an operator, is prefix, so we know this isn't that.
1519        let (span, kind) = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Bang,
    token_type: crate::parser::token_type::TokenType::Bang,
}exp!(Bang)) {
1520            // MACRO INVOCATION expression
1521            if qself.is_some() {
1522                self.dcx()
1523                    .emit_err(crate::diagnostics::MacroInvocationWithQualifiedPath(path.span));
1524            }
1525            let lo = path.span;
1526            let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });
1527            (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
1528        } else if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
1529            && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
1530        {
1531            if qself.is_some() {
1532                self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);
1533            }
1534            return expr;
1535        } else {
1536            (path.span, ExprKind::Path(qself, path))
1537        };
1538
1539        let expr = self.mk_expr(span, kind);
1540        self.maybe_recover_from_bad_qpath(expr)
1541    }
1542
1543    /// Parse `'label: $expr`. The label is already parsed.
1544    pub(super) fn parse_expr_labeled(
1545        &mut self,
1546        label_: Label,
1547        mut consume_colon: bool,
1548    ) -> PResult<'a, Box<Expr>> {
1549        let lo = label_.ident.span;
1550        let label = Some(label_);
1551        let ate_colon = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon));
1552        let tok_sp = self.token.span;
1553        let expr = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::While,
    token_type: crate::parser::token_type::TokenType::KwWhile,
}exp!(While)) {
1554            self.parse_expr_while(label, lo)
1555        } else if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::For,
    token_type: crate::parser::token_type::TokenType::KwFor,
}exp!(For)) {
1556            self.parse_expr_for(label, lo)
1557        } else if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Loop,
    token_type: crate::parser::token_type::TokenType::KwLoop,
}exp!(Loop)) {
1558            self.parse_expr_loop(label, lo)
1559        } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
1560            self.parse_expr_block(label, lo, BlockCheckMode::Default)
1561        } else if !ate_colon
1562            && self.may_recover()
1563            && (self.token.kind.close_delim().is_some() || self.token.is_punct())
1564            && could_be_unclosed_char_literal(label_.ident)
1565        {
1566            let (lit, _) =
1567                self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
1568                    self_.dcx().create_err(crate::diagnostics::UnexpectedTokenAfterLabel {
1569                        span: self_.token.span,
1570                        remove_label: None,
1571                        enclose_in_block: None,
1572                    })
1573                });
1574            consume_colon = false;
1575            Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
1576        } else if !ate_colon
1577            && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
1578        {
1579            // We're probably inside of a `Path<'a>` that needs a turbofish
1580            let guar = self.dcx().emit_err(crate::diagnostics::UnexpectedTokenAfterLabel {
1581                span: self.token.span,
1582                remove_label: None,
1583                enclose_in_block: None,
1584            });
1585            consume_colon = false;
1586            Ok(self.mk_expr_err(lo, guar))
1587        } else {
1588            let mut err = crate::diagnostics::UnexpectedTokenAfterLabel {
1589                span: self.token.span,
1590                remove_label: None,
1591                enclose_in_block: None,
1592            };
1593
1594            // Continue as an expression in an effort to recover on `'label: non_block_expr`.
1595            let expr = self.parse_expr().map(|expr| {
1596                let span = expr.span;
1597
1598                let found_labeled_breaks = {
1599                    struct FindLabeledBreaksVisitor;
1600
1601                    impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
1602                        type Result = ControlFlow<()>;
1603                        fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
1604                            if let ExprKind::Break(Some(_label), _) = ex.kind {
1605                                ControlFlow::Break(())
1606                            } else {
1607                                walk_expr(self, ex)
1608                            }
1609                        }
1610                    }
1611
1612                    FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
1613                };
1614
1615                // Suggestion involves adding a labeled block.
1616                //
1617                // If there are no breaks that may use this label, suggest removing the label and
1618                // recover to the unmodified expression.
1619                if !found_labeled_breaks {
1620                    err.remove_label = Some(lo.until(span));
1621
1622                    return expr;
1623                }
1624
1625                err.enclose_in_block = Some(crate::diagnostics::UnexpectedTokenAfterLabelSugg {
1626                    left: span.shrink_to_lo(),
1627                    right: span.shrink_to_hi(),
1628                });
1629
1630                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
1631                let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
1632                let blk = self.mk_block({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(stmt);
    vec
}thin_vec![stmt], BlockCheckMode::Default, span);
1633                self.mk_expr(span, ExprKind::Block(blk, label))
1634            });
1635
1636            self.dcx().emit_err(err);
1637            expr
1638        }?;
1639
1640        if !ate_colon && consume_colon {
1641            self.dcx().emit_err(crate::diagnostics::RequireColonAfterLabeledExpression {
1642                span: expr.span,
1643                label: lo,
1644                label_end: lo.between(tok_sp),
1645            });
1646        }
1647
1648        Ok(expr)
1649    }
1650
1651    /// Emit an error when a char is parsed as a lifetime or label because of a missing quote.
1652    pub(super) fn recover_unclosed_char<L>(
1653        &self,
1654        ident: Ident,
1655        mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1656        err: impl FnOnce(&Self) -> Diag<'a>,
1657    ) -> L {
1658        if !could_be_unclosed_char_literal(ident) {
    ::core::panicking::panic("assertion failed: could_be_unclosed_char_literal(ident)")
};assert!(could_be_unclosed_char_literal(ident));
1659        self.dcx()
1660            .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {
1661                err.span_suggestion_verbose(
1662                    ident.span.shrink_to_hi(),
1663                    "add `'` to close the char literal",
1664                    "'",
1665                    Applicability::MaybeIncorrect,
1666                );
1667            })
1668            .unwrap_or_else(|| {
1669                err(self)
1670                    .with_span_suggestion_verbose(
1671                        ident.span.shrink_to_hi(),
1672                        "add `'` to close the char literal",
1673                        "'",
1674                        Applicability::MaybeIncorrect,
1675                    )
1676                    .emit_err()
1677            });
1678        let name = ident.without_first_quote().name;
1679        mk_lit_char(name, ident.span)
1680    }
1681
1682    /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
1683    fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {
1684        let lo = self.token.span;
1685
1686        self.bump(); // `do`
1687        self.bump(); // `catch`
1688
1689        let span = lo.to(self.prev_token.span);
1690        self.dcx().emit_err(crate::diagnostics::DoCatchSyntaxRemoved { span });
1691
1692        self.parse_try_block(lo)
1693    }
1694
1695    /// Parse an expression if the token can begin one.
1696    fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {
1697        Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })
1698    }
1699
1700    /// Parse `"return" expr?`.
1701    fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {
1702        let lo = self.prev_token.span;
1703        let kind = ExprKind::Ret(self.parse_expr_opt()?);
1704        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1705        self.maybe_recover_from_bad_qpath(expr)
1706    }
1707
1708    /// Parse `"do" "yeet" expr?`.
1709    fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {
1710        let lo = self.token.span;
1711
1712        self.bump(); // `do`
1713        self.bump(); // `yeet`
1714
1715        let kind = ExprKind::Yeet(self.parse_expr_opt()?);
1716
1717        let span = lo.to(self.prev_token.span);
1718        self.psess.gated_spans.gate(sym::yeet_expr, span);
1719        let expr = self.mk_expr(span, kind);
1720        self.maybe_recover_from_bad_qpath(expr)
1721    }
1722
1723    /// Parse `"become" expr`, with `"become"` token already eaten.
1724    fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {
1725        let lo = self.prev_token.span;
1726        let kind = ExprKind::Become(self.parse_expr()?);
1727        let span = lo.to(self.prev_token.span);
1728        self.psess.gated_spans.gate(sym::explicit_tail_calls, span);
1729        let expr = self.mk_expr(span, kind);
1730        self.maybe_recover_from_bad_qpath(expr)
1731    }
1732
1733    /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
1734    /// If the label is followed immediately by a `:` token, the label and `:` are
1735    /// parsed as part of the expression (i.e. a labeled loop). The language team has
1736    /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
1737    /// the break expression of an unlabeled break is a labeled loop (as in
1738    /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
1739    /// expression only gets a warning for compatibility reasons; and a labeled break
1740    /// with a labeled loop does not even get a warning because there is no ambiguity.
1741    fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
1742        let lo = self.prev_token.span;
1743        let mut label = self.eat_label();
1744        let kind = if self.token == token::Colon
1745            && let Some(label) = label.take()
1746        {
1747            // The value expression can be a labeled loop, see issue #86948, e.g.:
1748            // `loop { break 'label: loop { break 'label 42; }; }`
1749            let lexpr = self.parse_expr_labeled(label, true)?;
1750            self.dcx().emit_err(crate::diagnostics::LabeledLoopInBreak {
1751                span: lexpr.span,
1752                sub: crate::diagnostics::WrapInParentheses::Expression {
1753                    left: lexpr.span.shrink_to_lo(),
1754                    right: lexpr.span.shrink_to_hi(),
1755                },
1756            });
1757            Some(lexpr)
1758        } else if self.token != token::OpenBrace
1759            || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
1760        {
1761            let mut expr = self.parse_expr_opt()?;
1762            if let Some(expr) = &mut expr {
1763                if label.is_some()
1764                    && match &expr.kind {
1765                        ExprKind::While(_, _, None)
1766                        | ExprKind::ForLoop(ForLoop { label: None, .. })
1767                        | ExprKind::Loop(_, None, _) => true,
1768                        ExprKind::Block(block, None) => {
1769                            #[allow(non_exhaustive_omitted_patterns)] match block.rules {
    BlockCheckMode::Default => true,
    _ => false,
}matches!(block.rules, BlockCheckMode::Default)
1770                        }
1771                        _ => false,
1772                    }
1773                {
1774                    let span = expr.span;
1775                    self.psess.buffer_lint(
1776                        BREAK_WITH_LABEL_AND_LOOP,
1777                        lo.to(expr.span),
1778                        ast::CRATE_NODE_ID,
1779                        crate::diagnostics::BreakWithLabelAndLoop {
1780                            sub: crate::diagnostics::BreakWithLabelAndLoopSub {
1781                                left: span.shrink_to_lo(),
1782                                right: span.shrink_to_hi(),
1783                            },
1784                        },
1785                    );
1786                }
1787
1788                // Recover `break label aaaaa`
1789                if self.may_recover()
1790                    && let ExprKind::Path(None, p) = &expr.kind
1791                    && let [segment] = &*p.segments
1792                    && let &ast::PathSegment { ident, args: None, .. } = segment
1793                    && let Some(next) = self.parse_expr_opt()?
1794                {
1795                    label = Some(self.recover_ident_into_label(ident));
1796                    *expr = next;
1797                }
1798            }
1799
1800            expr
1801        } else {
1802            None
1803        };
1804        let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
1805        self.maybe_recover_from_bad_qpath(expr)
1806    }
1807
1808    /// Parse `"continue" label?`.
1809    fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1810        let mut label = self.eat_label();
1811
1812        // Recover `continue label` -> `continue 'label`
1813        if self.may_recover()
1814            && label.is_none()
1815            && let Some((ident, _)) = self.token.ident()
1816        {
1817            self.bump();
1818            label = Some(self.recover_ident_into_label(ident));
1819        }
1820
1821        let kind = ExprKind::Continue(label);
1822        Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
1823    }
1824
1825    /// Parse `"yield" expr?`.
1826    fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {
1827        let lo = self.prev_token.span;
1828        let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
1829        let span = lo.to(self.prev_token.span);
1830        self.psess.gated_spans.gate(sym::yield_expr, span);
1831        let expr = self.mk_expr(span, kind);
1832        self.maybe_recover_from_bad_qpath(expr)
1833    }
1834
1835    pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1836        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1837
1838        let container = self.parse_ty()?;
1839        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
1840
1841        let fields = self.parse_floating_field_access()?;
1842        let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
1843
1844        if let Err(mut e) = self.expect_one_of(&[], &[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen)]) {
1845            if trailing_comma {
1846                e.note("unexpected third argument to offset_of");
1847            } else {
1848                e.note("offset_of expects dot-separated field and variant names");
1849            }
1850            e.emit();
1851        }
1852
1853        // Eat tokens until the macro call ends.
1854        if self.may_recover() {
1855            while !self.token.kind.is_close_delim_or_eof() {
1856                self.bump();
1857            }
1858        }
1859
1860        // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but
1861        //        it actually "improves" diagnostics slightly by not pointing into the wrapper macros.
1862        let span = lo.to(self.token.span);
1863        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
1864
1865        self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span));
1866
1867        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
1868    }
1869
1870    pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1871        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1872        let expr = self.parse_expr()?;
1873        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
1874        let ty = self.parse_ty()?;
1875        // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but
1876        //        it actually "improves" diagnostics slightly by not pointing into the wrapper macros.
1877        let span = lo.to(self.token.span);
1878        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
1879        self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span));
1880        Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
1881    }
1882
1883    pub(crate) fn parse_expr_unsafe_binder_cast(
1884        &mut self,
1885        lo: Span,
1886        kind: UnsafeBinderCastKind,
1887    ) -> PResult<'a, Box<Expr>> {
1888        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1889
1890        let expr = self.parse_expr()?;
1891        let ty = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) { Some(self.parse_ty()?) } else { None };
1892        // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but
1893        //        it actually "improves" diagnostics slightly by not pointing into the wrapper macros.
1894        let span = lo.to(self.token.span);
1895        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
1896        self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span));
1897        Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
1898    }
1899
1900    /// Returns a string literal if the next token is a string literal.
1901    /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
1902    /// and returns `None` if the next token is not literal at all.
1903    pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {
1904        match self.parse_opt_meta_item_lit() {
1905            Some(lit) => match lit.kind {
1906                ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
1907                    style,
1908                    symbol: lit.symbol,
1909                    suffix: lit.suffix,
1910                    span: lit.span,
1911                    symbol_unescaped,
1912                }),
1913                _ => Err(Some(lit)),
1914            },
1915            None => Err(None),
1916        }
1917    }
1918
1919    pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
1920        (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
1921    }
1922
1923    fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
1924        ast::MetaItemLit {
1925            symbol: name,
1926            suffix: None,
1927            kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
1928            span,
1929        }
1930    }
1931
1932    fn handle_missing_lit<L>(
1933        &mut self,
1934        mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1935    ) -> PResult<'a, L> {
1936        let token = self.token;
1937        let err = |self_: &Self| {
1938            let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unexpected token: {0}",
                super::token_descr(&token)))
    })format!("unexpected token: {}", super::token_descr(&token));
1939            self_.dcx().struct_span_err(token.span, msg)
1940        };
1941        // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that
1942        // makes sense.
1943        if let Some((ident, IdentKind::Normal)) = self.token.lifetime()
1944            && could_be_unclosed_char_literal(ident)
1945        {
1946            let lt = self.expect_lifetime();
1947            Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
1948        } else {
1949            Err(err(self))
1950        }
1951    }
1952
1953    pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
1954        self.parse_opt_token_lit()
1955            .ok_or(())
1956            .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
1957    }
1958
1959    pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
1960        self.parse_opt_meta_item_lit()
1961            .ok_or(())
1962            .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
1963    }
1964
1965    fn recover_after_dot(&mut self) {
1966        if self.token == token::Dot {
1967            // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
1968            // dot would follow an optional literal, so we do this unconditionally.
1969            let recovered = self.look_ahead(1, |next_token| {
1970                // If it's an integer that looks like a float, then recover as such.
1971                //
1972                // We will never encounter the exponent part of a floating
1973                // point literal here, since there's no use of the exponent
1974                // syntax that also constitutes a valid integer, so we need
1975                // not check for that.
1976                if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
1977                    next_token.kind
1978                    && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
1979                    && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
1980                    && self.token.span.hi() == next_token.span.lo()
1981                {
1982                    let s = String::from("0.") + symbol.as_str();
1983                    let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
1984                    Some(Token::new(kind, self.token.span.to(next_token.span)))
1985                } else {
1986                    None
1987                }
1988            });
1989            if let Some(recovered) = recovered {
1990                self.dcx().emit_err(crate::diagnostics::FloatLiteralRequiresIntegerPart {
1991                    span: recovered.span,
1992                    suggestion: recovered.span.shrink_to_lo(),
1993                });
1994                self.bump();
1995                self.token = recovered;
1996            }
1997        }
1998    }
1999
2000    /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and
2001    /// `Lit::from_token` (excluding unary negation).
2002    pub fn eat_token_lit(&mut self) -> Option<token::Lit> {
2003        let check_expr = |expr: Box<Expr>| {
2004            if let ast::ExprKind::Lit(token_lit) = expr.kind {
2005                Some(token_lit)
2006            } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
2007                && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
2008            {
2009                None
2010            } else {
2011                {
    ::core::panicking::panic_fmt(format_args!("unexpected reparsed expr/literal: {0:?}",
            expr.kind));
};panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
2012            }
2013        };
2014        match self.token.uninterpolate().kind {
2015            token::Ident(name, IdentKind::Normal | IdentKind::ForcedKeyword)
2016                if name.is_bool_lit() =>
2017            {
2018                self.bump();
2019                Some(token::Lit::new(token::Bool, name, None))
2020            }
2021            token::Literal(token_lit) => {
2022                self.bump();
2023                Some(token_lit)
2024            }
2025            token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
2026                let lit = self
2027                    .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2028                    .expect("metavar seq literal");
2029                check_expr(lit)
2030            }
2031            token::OpenInvisible(InvisibleOrigin::MetaVar(
2032                mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
2033            )) => {
2034                let expr = self
2035                    .eat_metavar_seq(mv_kind, |this| this.parse_expr())
2036                    .expect("metavar seq expr");
2037                check_expr(expr)
2038            }
2039            _ => None,
2040        }
2041    }
2042
2043    /// Matches `lit = true | false | token_lit`.
2044    /// Returns `None` if the next token is not a literal.
2045    fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> {
2046        self.recover_after_dot();
2047        let span = self.token.span;
2048        self.eat_token_lit().map(|token_lit| (token_lit, span))
2049    }
2050
2051    /// Matches `lit = true | false | token_lit`.
2052    /// Returns `None` if the next token is not a literal.
2053    fn parse_opt_meta_item_lit(&mut self) -> Option<MetaItemLit> {
2054        self.recover_after_dot();
2055        let span = self.token.span;
2056        let uninterpolated_span = self.token_uninterpolated_span();
2057        self.eat_token_lit().map(|token_lit| {
2058            match MetaItemLit::from_token_lit(token_lit, span) {
2059                Ok(lit) => lit,
2060                Err(err) => {
2061                    let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span);
2062                    // Pack possible quotes and prefixes from the original literal into
2063                    // the error literal's symbol so they can be pretty-printed faithfully.
2064                    let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
2065                    let symbol = Symbol::intern(&suffixless_lit.to_string());
2066                    let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
2067                    MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
2068                }
2069            }
2070        })
2071    }
2072
2073    /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
2074    /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
2075    pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> {
2076        if let Some(expr) = self.eat_metavar_seq_with_matcher(
2077            |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
    MetaVarKind::Expr { .. } => true,
    _ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
2078            |this| {
2079                // FIXME(nnethercote) The `expr` case should only match if
2080                // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing
2081                // an `UnOp::Neg` and an `ExprKind::Lit`, like how
2082                // `can_begin_literal_maybe_minus` works. But this method has
2083                // been over-accepting for a long time, and to make that change
2084                // here requires also changing some `parse_literal_maybe_minus`
2085                // call sites to accept additional expression kinds. E.g.
2086                // `ExprKind::Path` must be accepted when parsing range
2087                // patterns. That requires some care. So for now, we continue
2088                // being less strict here than we should be.
2089                this.parse_expr()
2090            },
2091        ) {
2092            return Ok(expr);
2093        } else if let Some(lit) =
2094            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2095        {
2096            return Ok(lit);
2097        }
2098
2099        let lo = self.token.span;
2100        let minus_present = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Minus,
    token_type: crate::parser::token_type::TokenType::Minus,
}exp!(Minus));
2101        let (token_lit, span) = self.parse_token_lit()?;
2102        let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
2103
2104        if minus_present {
2105            Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
2106        } else {
2107            Ok(expr)
2108        }
2109    }
2110
2111    /// Parses a block or unsafe block.
2112    pub(super) fn parse_expr_block(
2113        &mut self,
2114        opt_label: Option<Label>,
2115        lo: Span,
2116        blk_mode: BlockCheckMode,
2117    ) -> PResult<'a, Box<Expr>> {
2118        if self.token.is_metavar_block() {
2119            self.dcx().emit_err(crate::diagnostics::InvalidBlockMacroSegment {
2120                span: self.token.span,
2121                context: lo.to(self.token.span),
2122                wrap: crate::diagnostics::WrapInExplicitBlock {
2123                    lo: self.token.span.shrink_to_lo(),
2124                    hi: self.token.span.shrink_to_hi(),
2125                },
2126            });
2127        }
2128
2129        let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
2130        Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
2131    }
2132
2133    /// Parse a block which takes no attributes and has no label
2134    fn parse_simple_block(&mut self) -> PResult<'a, Box<Expr>> {
2135        let blk = self.parse_block()?;
2136        Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
2137    }
2138
2139    fn parse_expr_move(&mut self) -> PResult<'a, Box<Expr>> {
2140        let move_kw = self.token.span;
2141        self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Move,
    token_type: crate::parser::token_type::TokenType::KwMove,
}exp!(Move))?;
2142        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
2143        let expr = self.parse_expr()?;
2144        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
2145        let span = move_kw.to(self.prev_token.span);
2146        self.psess.gated_spans.gate(sym::move_expr, span);
2147        Ok(self.mk_expr(span, ExprKind::Move(expr, move_kw)))
2148    }
2149
2150    /// Parses a closure expression (e.g., `move |args| expr`).
2151    fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> {
2152        let lo = self.token.span;
2153
2154        let before = self.prev_token;
2155        let binder = if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::For,
    token_type: crate::parser::token_type::TokenType::KwFor,
}exp!(For)) {
2156            let lo = self.token.span;
2157            let (bound_vars, _) = self.parse_higher_ranked_binder()?;
2158            let span = lo.to(self.prev_token.span);
2159
2160            self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
2161
2162            ClosureBinder::For { span, generic_params: bound_vars }
2163        } else {
2164            ClosureBinder::NotPresent
2165        };
2166
2167        let constness = self.parse_closure_constness();
2168
2169        let movability = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Static,
    token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static)) {
2170            self.psess.gated_spans.gate(sym::coroutines, self.prev_token.span);
2171            Movability::Static
2172        } else {
2173            Movability::Movable
2174        };
2175
2176        let coroutine_marker = if self.token_uninterpolated_span().at_least_rust_2018() {
2177            self.parse_coroutine_marker(Case::Sensitive)
2178        } else {
2179            None
2180        };
2181
2182        if let ClosureBinder::NotPresent = binder
2183            && coroutine_marker.is_some()
2184        {
2185            // coroutine closures and generators can have the same qualifiers, so we might end up
2186            // in here if there is a missing `|` but also no `{`. Adjust the expectations in that case.
2187            self.expected_token_types.insert(TokenType::OpenBrace);
2188        }
2189
2190        let capture_clause = self.parse_capture_clause()?;
2191        let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
2192        let decl_hi = self.prev_token.span;
2193        let mut body = match &fn_decl.output {
2194            // No return type.
2195            FnRetTy::Default(_) => {
2196                let restrictions =
2197                    self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2198                let prev = self.prev_token;
2199                let token = self.token;
2200                match self.parse_expr_res(restrictions) {
2201                    Ok(expr) => expr,
2202                    Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
2203                }
2204            }
2205            // Explicit return type (`->`) needs block `-> T { }`.
2206            FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
2207        };
2208
2209        if let Some(coroutine_marker) = coroutine_marker
2210            && coroutine_marker.kind.is_gen()
2211        {
2212            // Feature-gate `gen ||` and `async gen ||` closures.
2213            // FIXME(gen_blocks): This perhaps should be a different gate.
2214            self.psess.gated_spans.gate(sym::gen_blocks, coroutine_marker.span);
2215        }
2216
2217        if self.token == TokenKind::Semi
2218            && let Some((Delimiter::Parenthesis, _)) = self.token_cursor.parent_delim_and_span()
2219            && self.may_recover()
2220        {
2221            // It is likely that the closure body is a block but where the
2222            // braces have been removed. We will recover and eat the next
2223            // statements later in the parsing process.
2224            body = self.mk_expr_err(
2225                body.span,
2226                self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
2227            );
2228        }
2229
2230        let body_span = body.span;
2231
2232        let closure = self.mk_expr(
2233            lo.to(body.span),
2234            ExprKind::Closure(Box::new(ast::Closure {
2235                binder,
2236                capture_clause,
2237                constness,
2238                coroutine_marker,
2239                movability,
2240                fn_decl,
2241                body,
2242                fn_decl_span: lo.to(decl_hi),
2243                fn_arg_span,
2244            })),
2245        );
2246
2247        // Disable recovery for closure body
2248        let spans =
2249            ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
2250        self.current_closure = Some(spans);
2251
2252        Ok(closure)
2253    }
2254
2255    /// If an explicit return type is given, require a block to appear (RFC 968).
2256    fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, Box<Expr>> {
2257        if self.may_recover()
2258            && self.token.can_begin_expr()
2259            && self.token.kind != TokenKind::OpenBrace
2260            && !self.token.is_metavar_block()
2261        {
2262            let snapshot = self.create_snapshot_for_diagnostic();
2263            let restrictions =
2264                self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2265            let tok = self.token.clone();
2266            match self.parse_expr_res(restrictions) {
2267                Ok(expr) => {
2268                    let descr = super::token_descr(&tok);
2269                    let mut diag = self
2270                        .dcx()
2271                        .struct_span_err(tok.span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("expected `{{`, found {0}", descr))
    })format!("expected `{{`, found {descr}"));
2272                    diag.span_label(
2273                        ret_span,
2274                        "explicit return type requires closure body to be enclosed in braces",
2275                    );
2276                    diag.multipart_suggestion(
2277                        "wrap the expression in curly braces",
2278                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(), "{ ".to_string()),
                (expr.span.shrink_to_hi(), " }".to_string())]))vec![
2279                            (expr.span.shrink_to_lo(), "{ ".to_string()),
2280                            (expr.span.shrink_to_hi(), " }".to_string()),
2281                        ],
2282                        Applicability::MachineApplicable,
2283                    );
2284                    diag.emit();
2285                    return Ok(expr);
2286                }
2287                Err(diag) => {
2288                    diag.cancel();
2289                    self.restore_snapshot(snapshot);
2290                }
2291            }
2292        }
2293
2294        let body_lo = self.token.span;
2295        self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2296    }
2297
2298    /// Parses an optional `move` or `use` prefix to a closure-like construct.
2299    fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
2300        if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Move,
    token_type: crate::parser::token_type::TokenType::KwMove,
}exp!(Move)) {
2301            let move_kw_span = self.prev_token.span;
2302            // Check for `move async` and recover
2303            if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Async,
    token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
2304                let move_async_span = self.token.span.with_lo(self.prev_token.span.lo());
2305                Err(self.dcx().create_err(crate::diagnostics::AsyncMoveOrderIncorrect {
2306                    span: move_async_span,
2307                }))
2308            } else {
2309                Ok(CaptureBy::Value { move_kw: move_kw_span })
2310            }
2311        } else if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Use,
    token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use)) {
2312            let use_kw_span = self.prev_token.span;
2313            self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2314            // Check for `use async` and recover
2315            if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Async,
    token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
2316                let use_async_span = self.token.span.with_lo(self.prev_token.span.lo());
2317                Err(self.dcx().create_err(crate::diagnostics::AsyncUseOrderIncorrect {
2318                    span: use_async_span,
2319                }))
2320            } else {
2321                Ok(CaptureBy::Use { use_kw: use_kw_span })
2322            }
2323        } else {
2324            Ok(CaptureBy::Ref)
2325        }
2326    }
2327
2328    /// Parses the `|arg, arg|` header of a closure.
2329    fn parse_fn_block_decl(&mut self) -> PResult<'a, (Box<FnDecl>, Span)> {
2330        let arg_start = self.token.span.lo();
2331
2332        let inputs = if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OrOr,
    token_type: crate::parser::token_type::TokenType::OrOr,
}exp!(OrOr)) {
2333            ThinVec::new()
2334        } else {
2335            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Or,
    token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or))?;
2336            let args = self
2337                .parse_seq_to_before_tokens(
2338                    &[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Or,
    token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)],
2339                    &[&token::OrOr],
2340                    SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2341                    |p| p.parse_fn_block_param(),
2342                )?
2343                .0;
2344            self.expect_or()?;
2345            args
2346        };
2347        let arg_span = self.prev_token.span.with_lo(arg_start);
2348        let output =
2349            self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
2350
2351        Ok((Box::new(FnDecl { inputs, output }), arg_span))
2352    }
2353
2354    /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
2355    fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
2356        let lo = self.token.span;
2357        let attrs = self.parse_outer_attributes()?;
2358        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
2359            let pat = Box::new(this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?);
2360            let ty = if this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Colon,
    token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
2361                this.parse_ty()?
2362            } else {
2363                this.mk_ty(pat.span, TyKind::Infer)
2364            };
2365
2366            Ok((
2367                Param {
2368                    attrs,
2369                    ty,
2370                    pat,
2371                    span: lo.to(this.prev_token.span),
2372                    id: DUMMY_NODE_ID,
2373                    is_placeholder: false,
2374                    has_const_keyword: false,
2375                },
2376                Trailing::from(this.token == token::Comma),
2377                UsePreAttrPos::No,
2378            ))
2379        })
2380    }
2381
2382    /// Parses an `if` expression (`if` token already eaten).
2383    fn parse_expr_if(&mut self) -> PResult<'a, Box<Expr>> {
2384        let lo = self.prev_token.span;
2385        // Scoping code checks the top level edition of the `if`; let's match it here.
2386        // The `CondChecker` also checks the edition of the `let` itself, just to make sure.
2387        let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2388        let cond = self.parse_expr_cond(let_chains_policy)?;
2389        self.parse_if_after_cond(lo, cond)
2390    }
2391
2392    fn parse_if_after_cond(&mut self, lo: Span, mut cond: Box<Expr>) -> PResult<'a, Box<Expr>> {
2393        let cond_span = cond.span;
2394        // Tries to interpret `cond` as either a missing expression if it's a block,
2395        // or as an unfinished expression if it's a binop and the RHS is a block.
2396        // We could probably add more recoveries here too...
2397        let mut recover_block_from_condition = |this: &mut Self| {
2398            let block = match &mut cond.kind {
2399                ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
2400                    if let ExprKind::Block(_, None) = right.kind =>
2401                {
2402                    let guar = this.dcx().emit_err(crate::diagnostics::IfExpressionMissingThenBlock {
2403                        if_span: lo,
2404                        missing_then_block_sub:
2405                            crate::diagnostics::IfExpressionMissingThenBlockSub::UnfinishedCondition(
2406                                cond_span.shrink_to_lo().to(*binop_span),
2407                            ),
2408                        let_else_sub: None,
2409                    });
2410                    std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
2411                }
2412                ExprKind::Block(_, None) => {
2413                    let guar =
2414                        this.dcx().emit_err(crate::diagnostics::IfExpressionMissingCondition {
2415                            if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
2416                            block_span: self.psess.source_map().start_point(cond_span),
2417                        });
2418                    std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
2419                }
2420                _ => {
2421                    return None;
2422                }
2423            };
2424            if let ExprKind::Block(block, _) = &block.kind {
2425                Some(block.clone())
2426            } else {
2427                ::core::panicking::unreachable_default_msg()unreachable!()
2428            }
2429        };
2430        // Parse then block
2431        let thn = if self.token.is_keyword(kw::Else) {
2432            if let Some(block) = recover_block_from_condition(self) {
2433                block
2434            } else {
2435                let let_else_sub = #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
    ExprKind::Let(..) => true,
    _ => false,
}matches!(cond.kind, ExprKind::Let(..)).then(|| {
2436                    crate::diagnostics::IfExpressionLetSomeSub { if_span: lo.until(cond_span) }
2437                });
2438
2439                let guar = self.dcx().emit_err(crate::diagnostics::IfExpressionMissingThenBlock {
2440                    if_span: lo,
2441                    missing_then_block_sub:
2442                        crate::diagnostics::IfExpressionMissingThenBlockSub::AddThenBlock(
2443                            cond_span.shrink_to_hi(),
2444                        ),
2445                    let_else_sub,
2446                });
2447                self.mk_block_err(cond_span.shrink_to_hi(), guar)
2448            }
2449        } else {
2450            let attrs = self.parse_outer_attributes()?; // For recovery.
2451            let maybe_fatarrow = self.token;
2452            let block = if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2453                self.parse_block()?
2454            } else if let Some(block) = recover_block_from_condition(self) {
2455                block
2456            } else {
2457                self.error_on_extra_if(&cond)?;
2458                // Parse block, which will always fail, but we can add a nice note to the error
2459                self.parse_block().map_err(|mut err| {
2460                        if self.prev_token == token::Semi
2461                            && self.token == token::AndAnd
2462                            && let maybe_let = self.look_ahead(1, |t| t.clone())
2463                            && maybe_let.is_keyword(kw::Let)
2464                        {
2465                            err.span_suggestion_verbose(
2466                                self.prev_token.span,
2467                                "consider removing this semicolon to parse the `let` as part of the same chain",
2468                                "",
2469                                Applicability::MachineApplicable,
2470                            ).span_note(
2471                                self.token.span.to(maybe_let.span),
2472                                "you likely meant to continue parsing the let-chain starting here",
2473                            );
2474                        } else {
2475                            if self.prev_token == token::Semi
2476                                && (self.token == token::OpenBrace || AssocOp::from_token(&self.token).is_some())
2477                            {
2478                                err.span_suggestion_verbose(
2479                                    self.prev_token.span,
2480                                    "remove this semicolon",
2481                                    "",
2482                                    Applicability::MaybeIncorrect,
2483                                );
2484                            }
2485
2486                            // Look for usages of '=>' where '>=' might be intended
2487                            if maybe_fatarrow == token::FatArrow {
2488                                err.span_suggestion_verbose(
2489                                    maybe_fatarrow.span,
2490                                    "you might have meant to write a \"greater than or equal to\" comparison",
2491                                    ">=",
2492                                    Applicability::MaybeIncorrect,
2493                                );
2494                            }
2495                            err.span_note(
2496                                cond_span,
2497                                "the `if` expression is missing a block after this condition",
2498                            );
2499                        }
2500                        err
2501                    })?
2502            };
2503            self.error_on_if_block_attrs(lo, false, block.span, attrs);
2504            block
2505        };
2506        let els = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Else,
    token_type: crate::parser::token_type::TokenType::KwElse,
}exp!(Else)) { Some(self.parse_expr_else()?) } else { None };
2507        Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2508    }
2509
2510    /// Parses the condition of a `if` or `while` expression.
2511    ///
2512    /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
2513    /// i.e. the same span we use to later decide whether the drop behaviour should be that of
2514    /// edition `..=2021` or that of `2024..`.
2515    // Public to use it for custom `if` expressions in rustfmt forks like https://github.com/tucant/rustfmt
2516    pub fn parse_expr_cond(
2517        &mut self,
2518        let_chains_policy: LetChainsPolicy,
2519    ) -> PResult<'a, Box<Expr>> {
2520        let mut cond =
2521            self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET)?;
2522
2523        let mut checker = CondChecker::new(self, let_chains_policy);
2524        checker.visit_expr(&mut cond);
2525        Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2526            self.mk_expr_err(cond.span, guar)
2527        } else {
2528            cond
2529        })
2530    }
2531
2532    /// Parses a `let $pat = $expr` pseudo-expression.
2533    fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
2534        let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2535            let err = crate::diagnostics::ExpectedExpressionFoundLet {
2536                span: self.token.span,
2537                reason: crate::diagnostics::ForbiddenLetReason::OtherForbidden,
2538                missing_let: None,
2539                comparison: None,
2540            };
2541            if self.prev_token == token::Or {
2542                // This was part of a closure, the that part of the parser recover.
2543                return Err(self.dcx().create_err(err));
2544            } else if AssocOp::from_token(&self.prev_token).is_some()
2545                || self.prev_token == token::Bang
2546            {
2547                // This was something like `- let`, we want to point at that.
2548                let mut err = self.dcx().create_err(err);
2549                err.span_label(self.prev_token.span, "expected an expression after this");
2550                Recovered::Yes(err.emit_err())
2551            } else {
2552                Recovered::Yes(self.dcx().emit_err(err))
2553            }
2554        } else {
2555            Recovered::No
2556        };
2557        self.bump(); // Eat `let` token
2558        let lo = self.prev_token.span;
2559        let pat = self.parse_pat_no_top_guard(
2560            None,
2561            RecoverComma::Yes,
2562            RecoverColon::Yes,
2563            CommaRecoveryMode::LikelyTuple,
2564        )?;
2565        if self.token == token::EqEq {
2566            self.dcx().emit_err(crate::diagnostics::ExpectedEqForLetExpr {
2567                span: self.token.span,
2568                sugg_span: self.token.span,
2569            });
2570            self.bump();
2571        } else {
2572            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq))?;
2573        }
2574        let expr = self.parse_expr_assoc(Bound::Excluded(prec_let_scrutinee_needs_par()))?;
2575        let span = lo.to(expr.span);
2576        Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered)))
2577    }
2578
2579    /// Parses an `else { ... }` expression (`else` token already eaten).
2580    fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> {
2581        let else_span = self.prev_token.span; // `else`
2582        let attrs = self.parse_outer_attributes()?; // For recovery.
2583        let expr = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::If,
    token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If)) {
2584            self.parse_expr_if()?
2585        } else if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2586            self.parse_simple_block()?
2587        } else {
2588            let snapshot = self.create_snapshot_for_diagnostic();
2589            let first_tok = super::token_descr(&self.token);
2590            let first_tok_span = self.token.span;
2591            match self.parse_expr() {
2592                Ok(cond)
2593                // Try to guess the difference between a "condition-like" vs
2594                // "statement-like" expression.
2595                //
2596                // We are seeing the following code, in which $cond is neither
2597                // ExprKind::Block nor ExprKind::If (the 2 cases wherein this
2598                // would be valid syntax).
2599                //
2600                //     if ... {
2601                //     } else $cond
2602                //
2603                // If $cond is "condition-like" such as ExprKind::Binary, we
2604                // want to suggest inserting `if`.
2605                //
2606                //     if ... {
2607                //     } else if a == b {
2608                //            ^^
2609                //     }
2610                //
2611                // We account for macro calls that were meant as conditions as well.
2612                //
2613                //     if ... {
2614                //     } else if macro! { foo bar } {
2615                //            ^^
2616                //     }
2617                //
2618                // If $cond is "statement-like" such as ExprKind::While then we
2619                // want to suggest wrapping in braces.
2620                //
2621                //     if ... {
2622                //     } else {
2623                //            ^
2624                //         while true {}
2625                //     }
2626                //     ^
2627                    if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
2628                        && (classify::expr_requires_semi_to_be_stmt(&cond)
2629                            || #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
    ExprKind::MacCall(..) => true,
    _ => false,
}matches!(cond.kind, ExprKind::MacCall(..)))
2630                    =>
2631                {
2632                    self.dcx().emit_err(crate::diagnostics::ExpectedElseBlock {
2633                        first_tok_span,
2634                        first_tok,
2635                        else_span,
2636                        condition_start: cond.span.shrink_to_lo(),
2637                    });
2638                    self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2639                }
2640                Err(e) => {
2641                    e.cancel();
2642                    self.restore_snapshot(snapshot);
2643                    self.parse_simple_block()?
2644                },
2645                Ok(_) => {
2646                    self.restore_snapshot(snapshot);
2647                    self.parse_simple_block()?
2648                },
2649            }
2650        };
2651        self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2652        Ok(expr)
2653    }
2654
2655    fn error_on_if_block_attrs(
2656        &self,
2657        ctx_span: Span,
2658        is_ctx_else: bool,
2659        branch_span: Span,
2660        attrs: AttrWrapper,
2661    ) {
2662        if !attrs.is_empty()
2663            && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2664        {
2665            let attributes = x0.span.until(branch_span);
2666            let last = xn.span;
2667            let ctx = if is_ctx_else { "else" } else { "if" };
2668            self.dcx().emit_err(crate::diagnostics::OuterAttributeNotAllowedOnIfElse {
2669                last,
2670                branch_span,
2671                ctx_span,
2672                ctx: ctx.to_string(),
2673                attributes,
2674            });
2675        }
2676    }
2677
2678    fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> {
2679        if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2680            && let BinOpKind::And = binop
2681            && let ExprKind::If(cond, ..) = &right.kind
2682        {
2683            Err(self.dcx().create_err(crate::diagnostics::UnexpectedIfWithIf(
2684                binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2685            )))
2686        } else {
2687            Ok(())
2688        }
2689    }
2690
2691    // Public to use it for custom `for` expressions in rustfmt forks like https://github.com/tucant/rustfmt
2692    pub fn parse_for_head(&mut self) -> PResult<'a, (Pat, Box<Expr>)> {
2693        let begin_paren = if self.token == token::OpenParen {
2694            // Record whether we are about to parse `for (`.
2695            // This is used below for recovery in case of `for ( $stuff ) $block`
2696            // in which case we will suggest `for $stuff $block`.
2697            let start_span = self.token.span;
2698            let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2699            Some((start_span, left))
2700        } else {
2701            None
2702        };
2703        // Try to parse the pattern `for ($PAT) in $EXPR`.
2704        let pat = match (
2705            self.parse_pat_allow_top_guard(
2706                None,
2707                RecoverComma::Yes,
2708                RecoverColon::Yes,
2709                CommaRecoveryMode::LikelyTuple,
2710            ),
2711            begin_paren,
2712        ) {
2713            (Ok(pat), _) => pat, // Happy path.
2714            (Err(err), Some((start_span, left))) if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::In,
    token_type: crate::parser::token_type::TokenType::KwIn,
}exp!(In)) => {
2715                // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
2716                // happen right before the return of this method.
2717                let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL) {
2718                    Ok(expr) => expr,
2719                    Err(expr_err) => {
2720                        // We don't know what followed the `in`, so cancel and bubble up the
2721                        // original error.
2722                        expr_err.cancel();
2723                        return Err(err);
2724                    }
2725                };
2726                return if self.token == token::CloseParen {
2727                    // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
2728                    // parser state and emit a targeted suggestion.
2729                    let span = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [start_span, self.token.span]))vec![start_span, self.token.span];
2730                    let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2731                    self.bump(); // )
2732                    err.cancel();
2733                    self.dcx().emit_err(crate::diagnostics::ParenthesesInForHead {
2734                        span,
2735                        // With e.g. `for (x) in y)` this would replace `(x) in y)`
2736                        // with `x) in y)` which is syntactically invalid.
2737                        // However, this is prevented before we get here.
2738                        sugg: crate::diagnostics::ParenthesesInForHeadSugg { left, right },
2739                    });
2740                    Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
2741                } else {
2742                    Err(err) // Some other error, bubble up.
2743                };
2744            }
2745            (Err(err), _) => return Err(err), // Some other error, bubble up.
2746        };
2747        if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::In,
    token_type: crate::parser::token_type::TokenType::KwIn,
}exp!(In)) {
2748            self.error_missing_in_for_loop();
2749        }
2750        self.check_for_for_in_in_typo(self.prev_token.span);
2751        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
2752        Ok((pat, expr))
2753    }
2754
2755    /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
2756    fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2757        let is_await =
2758            self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Await,
    token_type: crate::parser::token_type::TokenType::KwAwait,
}exp!(Await));
2759
2760        if is_await {
2761            self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
2762        }
2763
2764        let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
2765
2766        let (pat, expr) = self.parse_for_head()?;
2767        let pat = Box::new(pat);
2768        // Recover from missing expression in `for` loop
2769        if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    ExprKind::Block(..) => true,
    _ => false,
}matches!(expr.kind, ExprKind::Block(..))
2770            && self.token.kind != token::OpenBrace
2771            && self.may_recover()
2772        {
2773            let guar = self.dcx().emit_err(crate::diagnostics::MissingExpressionInForLoop {
2774                span: expr.span.shrink_to_lo(),
2775            });
2776            let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
2777            let block = self.mk_block(::thin_vec::ThinVec::new()thin_vec![], BlockCheckMode::Default, self.prev_token.span);
2778            return Ok(self.mk_expr(
2779                lo.to(self.prev_token.span),
2780                ExprKind::ForLoop(Box::new(ForLoop {
2781                    pat,
2782                    iter: err_expr,
2783                    body: block,
2784                    label: opt_label,
2785                    kind,
2786                })),
2787            ));
2788        }
2789
2790        let (attrs, loop_block) = self.parse_inner_attrs_and_block(
2791            // Only suggest moving erroneous block label to the loop header
2792            // if there is not already a label there
2793            opt_label.is_none().then_some(lo),
2794        )?;
2795
2796        let kind = ExprKind::ForLoop(Box::new(ForLoop {
2797            pat,
2798            iter: expr,
2799            body: loop_block,
2800            label: opt_label,
2801            kind,
2802        }));
2803
2804        self.recover_loop_else("for", lo)?;
2805
2806        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
2807    }
2808
2809    /// Recovers from an `else` clause after a loop (`for...else`, `while...else`)
2810    fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
2811        if self.token.is_keyword(kw::Else) && self.may_recover() {
2812            let else_span = self.token.span;
2813            self.bump();
2814            let else_clause = self.parse_expr_else()?;
2815            self.dcx().emit_err(crate::diagnostics::LoopElseNotSupported {
2816                span: else_span.to(else_clause.span),
2817                loop_kind,
2818                loop_kw,
2819            });
2820        }
2821        Ok(())
2822    }
2823
2824    fn error_missing_in_for_loop(&mut self) {
2825        let (span, sub) = if self.token.is_ident_named(sym::of) {
2826            // Possibly using JS syntax (#75311).
2827            let span = self.token.span;
2828            self.bump();
2829            (span, Some(crate::diagnostics::MissingInInForLoopSub::InNotOf(span)))
2830        } else if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
2831            let span = self.prev_token.span;
2832            (span, Some(crate::diagnostics::MissingInInForLoopSub::InNotEq(span)))
2833        } else {
2834            let span = self.prev_token.span.between(self.token.span);
2835            let sub = (!self.for_loop_head_has_in())
2836                .then_some(crate::diagnostics::MissingInInForLoopSub::AddIn(span));
2837            (span, sub)
2838        };
2839
2840        self.dcx().emit_err(crate::diagnostics::MissingInInForLoop { span, sub });
2841    }
2842
2843    /// Whether the `for` loop header already contains an `in` before its body.
2844    /// If it does, the binding is malformed (e.g. `for i i in 0..10`) rather
2845    /// than missing `in`, so suggesting another `in` would just be invalid too.
2846    fn for_loop_head_has_in(&self) -> bool {
2847        let mut dist = 0;
2848        loop {
2849            let (is_in, is_end) = self.look_ahead(dist, |t| {
2850                (t.is_keyword(kw::In), #[allow(non_exhaustive_omitted_patterns)] match t.kind {
    token::OpenBrace | token::Eof => true,
    _ => false,
}matches!(t.kind, token::OpenBrace | token::Eof))
2851            });
2852            if is_in {
2853                return true;
2854            }
2855            if is_end {
2856                return false;
2857            }
2858            dist += 1;
2859        }
2860    }
2861
2862    /// Parses a `while` or `while let` expression (`while` token already eaten).
2863    fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2864        let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2865        let cond = self.parse_expr_cond(policy).map_err(|mut err| {
2866            err.span_label(lo, "while parsing the condition of this `while` expression");
2867            err
2868        })?;
2869        let (attrs, body) = self
2870            .parse_inner_attrs_and_block(
2871                // Only suggest moving erroneous block label to the loop header
2872                // if there is not already a label there
2873                opt_label.is_none().then_some(lo),
2874            )
2875            .map_err(|mut err| {
2876                err.span_label(lo, "while parsing the body of this `while` expression");
2877                err.span_label(cond.span, "this `while` condition successfully parsed");
2878                err
2879            })?;
2880
2881        self.recover_loop_else("while", lo)?;
2882
2883        Ok(self.mk_expr_with_attrs(
2884            lo.to(self.prev_token.span),
2885            ExprKind::While(cond, body, opt_label),
2886            attrs,
2887        ))
2888    }
2889
2890    /// Parses `loop { ... }` (`loop` token already eaten).
2891    fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2892        let loop_span = self.prev_token.span;
2893        let (attrs, body) = self.parse_inner_attrs_and_block(
2894            // Only suggest moving erroneous block label to the loop header
2895            // if there is not already a label there
2896            opt_label.is_none().then_some(lo),
2897        )?;
2898        self.recover_loop_else("loop", lo)?;
2899        Ok(self.mk_expr_with_attrs(
2900            lo.to(self.prev_token.span),
2901            ExprKind::Loop(body, opt_label, loop_span),
2902            attrs,
2903        ))
2904    }
2905
2906    pub(crate) fn eat_label(&mut self) -> Option<Label> {
2907        if let Some((ident, kind)) = self.token.lifetime() {
2908            // Disallow `'fn`, but with a better error message than `expect_lifetime`.
2909            if kind == IdentKind::Normal && ident.without_first_quote().is_reserved() {
2910                self.dcx().emit_err(crate::diagnostics::KeywordLabel { span: ident.span });
2911            }
2912
2913            self.bump();
2914            Some(Label { ident })
2915        } else {
2916            None
2917        }
2918    }
2919
2920    /// Parses a `match ... { ... }` expression (`match` token already eaten).
2921    fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> {
2922        let match_span = self.prev_token.span;
2923        let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
2924
2925        self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
2926    }
2927
2928    /// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
2929    /// expression. This is after the match token and scrutinee are eaten
2930    fn parse_match_block(
2931        &mut self,
2932        lo: Span,
2933        match_span: Span,
2934        scrutinee: Box<Expr>,
2935        match_kind: MatchKind,
2936    ) -> PResult<'a, Box<Expr>> {
2937        if let Err(mut e) = self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2938            if self.token == token::Semi {
2939                e.span_suggestion_short(
2940                    match_span,
2941                    "try removing this `match`",
2942                    "",
2943                    Applicability::MaybeIncorrect, // speculative
2944                );
2945            }
2946            if self.maybe_recover_unexpected_block_label(None) {
2947                e.cancel();
2948                self.bump();
2949            } else {
2950                return Err(e);
2951            }
2952        }
2953        let attrs = self.parse_inner_attributes()?;
2954
2955        let mut arms = ThinVec::new();
2956        while self.token != token::CloseBrace {
2957            match self.parse_arm() {
2958                Ok(arm) => arms.push(arm),
2959                Err(e) => {
2960                    // Recover by skipping to the end of the block.
2961                    let guar = e.emit_err();
2962                    self.recover_stmt();
2963                    let span = lo.to(self.token.span);
2964                    if self.token == token::CloseBrace {
2965                        self.bump();
2966                    }
2967                    // Always push at least one arm to make the match non-empty
2968                    arms.push(Arm {
2969                        attrs: Default::default(),
2970                        pat: Box::new(self.mk_pat(span, ast::PatKind::Err(guar))),
2971                        guard: None,
2972                        body: Some(self.mk_expr_err(span, guar)),
2973                        span,
2974                        id: DUMMY_NODE_ID,
2975                        is_placeholder: false,
2976                    });
2977                    return Ok(self.mk_expr_with_attrs(
2978                        span,
2979                        ExprKind::Match(scrutinee, arms, match_kind),
2980                        attrs,
2981                    ));
2982                }
2983            }
2984        }
2985        let hi = self.token.span;
2986        self.bump();
2987        Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
2988    }
2989
2990    /// Attempt to recover from match arm body with statements and no surrounding braces.
2991    fn parse_arm_body_missing_braces(
2992        &mut self,
2993        first_expr: &Box<Expr>,
2994        arrow_span: Span,
2995    ) -> Option<(Span, ErrorGuaranteed)> {
2996        if self.token != token::Semi {
2997            return None;
2998        }
2999        let start_snapshot = self.create_snapshot_for_diagnostic();
3000        let semi_sp = self.token.span;
3001        self.bump(); // `;`
3002        let mut stmts =
3003            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self.mk_stmt(first_expr.span,
                    ast::StmtKind::Expr(first_expr.clone()))]))vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
3004        let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3005            let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3006
3007            let guar = this.dcx().emit_err(crate::diagnostics::MatchArmBodyWithoutBraces {
3008                statements: span,
3009                arrow: arrow_span,
3010                num_statements: stmts.len(),
3011                sub: if stmts.len() > 1 {
3012                    crate::diagnostics::MatchArmBodyWithoutBracesSugg::AddBraces {
3013                        left: span.shrink_to_lo(),
3014                        right: span.shrink_to_hi(),
3015                        num_statements: stmts.len(),
3016                    }
3017                } else {
3018                    crate::diagnostics::MatchArmBodyWithoutBracesSugg::UseComma {
3019                        semicolon: semi_sp,
3020                    }
3021                },
3022            });
3023            (span, guar)
3024        };
3025        // We might have either a `,` -> `;` typo, or a block without braces. We need
3026        // a more subtle parsing strategy.
3027        loop {
3028            if self.token == token::CloseBrace {
3029                // We have reached the closing brace of the `match` expression.
3030                return Some(err(self, stmts));
3031            }
3032            if self.token == token::Comma {
3033                self.restore_snapshot(start_snapshot);
3034                return None;
3035            }
3036            let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3037            match self.parse_pat_no_top_alt(None, None) {
3038                Ok(_pat) => {
3039                    if self.token == token::FatArrow {
3040                        // Reached arm end.
3041                        self.restore_snapshot(pre_pat_snapshot);
3042                        return Some(err(self, stmts));
3043                    }
3044                }
3045                Err(err) => {
3046                    err.cancel();
3047                }
3048            }
3049
3050            self.restore_snapshot(pre_pat_snapshot);
3051            match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3052                // Consume statements for as long as possible.
3053                Ok(stmt) => {
3054                    stmts.push(stmt);
3055                }
3056                // We couldn't parse either yet another statement missing it's
3057                // enclosing block nor the next arm's pattern or closing brace.
3058                Err(stmt_err) => {
3059                    stmt_err.cancel();
3060                    self.restore_snapshot(start_snapshot);
3061                    break;
3062                }
3063            }
3064        }
3065        None
3066    }
3067
3068    pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3069        let attrs = self.parse_outer_attributes()?;
3070        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3071            let lo = this.token.span;
3072            let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3073            let pat = Box::new(pat);
3074
3075            let span_before_body = this.prev_token.span;
3076            let arm_body;
3077            let is_fat_arrow = this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::FatArrow,
    token_type: crate::parser::token_type::TokenType::FatArrow,
}exp!(FatArrow));
3078            let is_almost_fat_arrow =
3079                TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3080
3081            // this avoids the compiler saying that a `,` or `}` was expected even though
3082            // the pattern isn't a never pattern (and thus an arm body is required)
3083            let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3084                || #[allow(non_exhaustive_omitted_patterns)] match this.token.kind {
    token::Comma | token::CloseBrace => true,
    _ => false,
}matches!(this.token.kind, token::Comma | token::CloseBrace);
3085
3086            let mut result = if armless {
3087                // A pattern without a body, allowed for never patterns.
3088                arm_body = None;
3089                let span = lo.to(this.prev_token.span);
3090                this.expect_one_of(&[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)], &[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)]).map(|x| {
3091                    // Don't gate twice
3092                    if !pat.contains_never_pattern() {
3093                        this.psess.gated_spans.gate(sym::never_patterns, span);
3094                    }
3095                    x
3096                })
3097            } else {
3098                if let Err(mut err) = this.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::FatArrow,
    token_type: crate::parser::token_type::TokenType::FatArrow,
}exp!(FatArrow)) {
3099                    // We might have a `=>` -> `=` or `->` typo (issue #89396).
3100                    if is_almost_fat_arrow {
3101                        err.span_suggestion_verbose(
3102                            this.token.span,
3103                            "use a fat arrow to start a match arm",
3104                            "=>",
3105                            Applicability::MachineApplicable,
3106                        );
3107                        if #[allow(non_exhaustive_omitted_patterns)] match (&this.prev_token.kind,
        &this.token.kind) {
    (token::DotDotEq, token::Gt) => true,
    _ => false,
}matches!(
3108                            (&this.prev_token.kind, &this.token.kind),
3109                            (token::DotDotEq, token::Gt)
3110                        ) {
3111                            // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
3112                            // so we suppress the error here
3113                            err.delay_as_bug();
3114                        } else {
3115                            err.emit();
3116                        }
3117                        this.bump();
3118                    } else {
3119                        return Err(err);
3120                    }
3121                }
3122                let arrow_span = this.prev_token.span;
3123                let arm_start_span = this.token.span;
3124
3125                let expr =
3126                    this.parse_expr_res(Restrictions::STMT_EXPR).map_err(|mut err| {
3127                        err.span_label(arrow_span, "while parsing the `match` arm starting here");
3128                        err
3129                    })?;
3130
3131                let require_comma =
3132                    !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3133
3134                if !require_comma {
3135                    arm_body = Some(expr);
3136                    // Eat a comma if it exists, though.
3137                    let _ = this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3138                    Ok(Recovered::No)
3139                } else if let Some((span, guar)) =
3140                    this.parse_arm_body_missing_braces(&expr, arrow_span)
3141                {
3142                    let body = this.mk_expr_err(span, guar);
3143                    arm_body = Some(body);
3144                    Ok(Recovered::Yes(guar))
3145                } else {
3146                    let expr_span = expr.span;
3147                    arm_body = Some(expr);
3148                    this.expect_one_of(&[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)], &[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)]).map_err(|mut err| {
3149                        if this.token == token::FatArrow {
3150                            let sm = this.psess.source_map();
3151                            if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3152                                && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3153                                && expr_lines.lines.len() == 2
3154                            {
3155                                if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3156                                    // We check whether there's any trailing code in the parse span,
3157                                    // if there isn't, we very likely have the following:
3158                                    //
3159                                    // X |     &Y => "y"
3160                                    //   |        --    - missing comma
3161                                    //   |        |
3162                                    //   |        arrow_span
3163                                    // X |     &X => "x"
3164                                    //   |      - ^^ self.token.span
3165                                    //   |      |
3166                                    //   |      parsed until here as `"y" & X`
3167                                    err.span_suggestion_short(
3168                                        arm_start_span.shrink_to_hi(),
3169                                        "missing a comma here to end this `match` arm",
3170                                        ",",
3171                                        Applicability::MachineApplicable,
3172                                    );
3173                                } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3174                                    == expr_lines.lines[0].end_col
3175                                {
3176                                    // similar to the above, but we may typo a `.` or `/` at the end of the line
3177                                    let comma_span = arm_start_span
3178                                        .shrink_to_hi()
3179                                        .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3180                                    if let Ok(res) = sm.span_to_snippet(comma_span)
3181                                        && (res == "." || res == "/")
3182                                    {
3183                                        err.span_suggestion_short(
3184                                            comma_span,
3185                                            "you might have meant to write a `,` to end this `match` arm",
3186                                            ",",
3187                                            Applicability::MachineApplicable,
3188                                        );
3189                                    }
3190                                }
3191                            }
3192                        } else {
3193                            err.span_label(
3194                                arrow_span,
3195                                "while parsing the `match` arm starting here",
3196                            );
3197                        }
3198                        err
3199                    })
3200                }
3201            };
3202
3203            let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3204            let arm_span = lo.to(hi_span);
3205
3206            // We want to recover:
3207            // X |     Some(_) => foo()
3208            //   |                     - missing comma
3209            // X |     None => "x"
3210            //   |     ^^^^ self.token.span
3211            // as well as:
3212            // X |     Some(!)
3213            //   |            - missing comma
3214            // X |     None => "x"
3215            //   |     ^^^^ self.token.span
3216            // But we musn't recover
3217            // X |     pat[0] => {}
3218            //   |        ^ self.token.span
3219            let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3220            if recover_missing_comma {
3221                result = result.or_else(|err| {
3222                    // FIXME(compiler-errors): We could also recover `; PAT =>` here
3223
3224                    // Try to parse a following `PAT =>`, if successful
3225                    // then we should recover.
3226                    let mut snapshot = this.create_snapshot_for_diagnostic();
3227                    let pattern_follows = snapshot
3228                        .parse_pat_no_top_guard(
3229                            None,
3230                            RecoverComma::Yes,
3231                            RecoverColon::Yes,
3232                            CommaRecoveryMode::EitherTupleOrPipe,
3233                        )
3234                        .map_err(|err| err.cancel())
3235                        .is_ok();
3236                    if pattern_follows && snapshot.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::FatArrow,
    token_type: crate::parser::token_type::TokenType::FatArrow,
}exp!(FatArrow)) {
3237                        err.cancel();
3238                        let guar = this.dcx().emit_err(crate::diagnostics::MissingCommaAfterMatchArm {
3239                            span: arm_span.shrink_to_hi(),
3240                        });
3241                        return Ok(Recovered::Yes(guar));
3242                    }
3243                    Err(err)
3244                });
3245            }
3246            result?;
3247
3248            Ok((
3249                ast::Arm {
3250                    attrs,
3251                    pat,
3252                    guard,
3253                    body: arm_body,
3254                    span: arm_span,
3255                    id: DUMMY_NODE_ID,
3256                    is_placeholder: false,
3257                },
3258                Trailing::No,
3259                UsePreAttrPos::No,
3260            ))
3261        })
3262    }
3263
3264    pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
3265        self.eat_metavar_seq(MetaVarKind::Guard, |this| {
3266            this.expect_match_arm_guard(ForceCollect::Yes)
3267        })
3268    }
3269
3270    fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
3271        if let Some(guard) = self.eat_metavar_guard() {
3272            return Ok(Some(guard));
3273        }
3274
3275        if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::If,
    token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If)) {
3276            // No match arm guard present.
3277            return Ok(None);
3278        }
3279        self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
3280    }
3281
3282    pub(crate) fn expect_match_arm_guard(
3283        &mut self,
3284        force_collect: ForceCollect,
3285    ) -> PResult<'a, Box<Guard>> {
3286        if let Some(guard) = self.eat_metavar_guard() {
3287            return Ok(guard);
3288        }
3289
3290        self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::If,
    token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If))?;
3291        self.expect_match_arm_guard_cond(force_collect)
3292    }
3293
3294    fn expect_match_arm_guard_cond(
3295        &mut self,
3296        force_collect: ForceCollect,
3297    ) -> PResult<'a, Box<Guard>> {
3298        let leading_if_span = self.prev_token.span;
3299
3300        let mut cond = self.parse_match_guard_condition(force_collect)?;
3301        let cond_span = cond.span;
3302
3303        CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3304
3305        let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
3306        Ok(Box::new(guard))
3307    }
3308
3309    fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
3310        if self.token == token::OpenParen {
3311            let left = self.token.span;
3312            let pat = self.parse_pat_no_top_guard(
3313                None,
3314                RecoverComma::Yes,
3315                RecoverColon::Yes,
3316                CommaRecoveryMode::EitherTupleOrPipe,
3317            )?;
3318            if let ast::PatKind::Paren(subpat) = &pat.kind
3319                && let ast::PatKind::Guard(..) = &subpat.kind
3320            {
3321                // Detect and recover from `($pat if $cond) => $arm`.
3322                // FIXME(guard_patterns): convert this to a normal guard instead
3323                let span = pat.span;
3324                let ast::PatKind::Paren(subpat) = pat.kind else { ::core::panicking::unreachable_default_msg()unreachable!() };
3325                let ast::PatKind::Guard(_, mut guard) = subpat.kind else { ::core::panicking::unreachable_default_msg()unreachable!() };
3326                self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
3327                let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3328                checker.visit_expr(&mut guard.cond);
3329
3330                let right = self.prev_token.span;
3331                self.dcx().emit_err(crate::diagnostics::ParenthesesInMatchPat {
3332                    span: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [left, right]))vec![left, right],
3333                    sugg: crate::diagnostics::ParenthesesInMatchPatSugg { left, right },
3334                });
3335
3336                if let Some(guar) = checker.found_incorrect_let_chain {
3337                    guard.cond = *self.mk_expr_err(guard.span(), guar);
3338                }
3339                Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
3340            } else {
3341                Ok((pat, self.parse_match_arm_guard()?))
3342            }
3343        } else {
3344            // Regular parser flow:
3345            let pat = self.parse_pat_no_top_guard(
3346                None,
3347                RecoverComma::Yes,
3348                RecoverColon::Yes,
3349                CommaRecoveryMode::EitherTupleOrPipe,
3350            )?;
3351            Ok((pat, self.parse_match_arm_guard()?))
3352        }
3353    }
3354
3355    fn parse_match_guard_condition(
3356        &mut self,
3357        force_collect: ForceCollect,
3358    ) -> PResult<'a, Box<Expr>> {
3359        let attrs = self.parse_outer_attributes()?;
3360        let expr = self.collect_tokens(
3361            None,
3362            AttrWrapper::empty(),
3363            force_collect,
3364            |this, _empty_attrs| {
3365                match this.parse_expr_res_after_attrs(
3366                    Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD,
3367                    attrs,
3368                ) {
3369                    Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
3370                    Err(mut err) => {
3371                        if this.prev_token == token::OpenBrace {
3372                            let sugg_sp = this.prev_token.span.shrink_to_lo();
3373                            // Consume everything within the braces, let's avoid further parse
3374                            // errors.
3375                            this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3376                            let msg =
3377                                "you might have meant to start a match arm after the match guard";
3378                            if this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
3379                                let applicability = if this.token != token::FatArrow {
3380                                    // We have high confidence that we indeed didn't have a struct
3381                                    // literal in the match guard, but rather we had some operation
3382                                    // that ended in a path, immediately followed by a block that was
3383                                    // meant to be the match arm.
3384                                    Applicability::MachineApplicable
3385                                } else {
3386                                    Applicability::MaybeIncorrect
3387                                };
3388                                err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3389                            }
3390                        }
3391                        Err(err)
3392                    }
3393                }
3394            },
3395        )?;
3396        Ok(expr)
3397    }
3398
3399    /// Parses a `try {...}` or `try bikeshed Ty {...}` expression (`try` token already eaten).
3400    fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> {
3401        let annotation =
3402            if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::sym::bikeshed,
    token_type: crate::parser::token_type::TokenType::SymBikeshed,
}exp!(Bikeshed)) { Some(self.parse_ty()?) } else { None };
3403
3404        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3405        if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Catch,
    token_type: crate::parser::token_type::TokenType::KwCatch,
}exp!(Catch)) {
3406            Err(self
3407                .dcx()
3408                .create_err(crate::diagnostics::CatchAfterTry { span: self.prev_token.span }))
3409        } else {
3410            let span = span_lo.to(body.span);
3411            let gate_sym =
3412                if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous };
3413            self.psess.gated_spans.gate(gate_sym, span);
3414            Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs))
3415        }
3416    }
3417
3418    fn is_do_catch_block(&self) -> bool {
3419        self.token.is_keyword(kw::Do)
3420            && self.is_keyword_ahead(1, &[kw::Catch])
3421            && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3422            && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3423    }
3424
3425    fn is_do_yeet(&self) -> bool {
3426        self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3427    }
3428
3429    fn is_try_block(&self) -> bool {
3430        self.token.is_keyword(kw::Try)
3431            && self.look_ahead(1, |t| {
3432                *t == token::OpenBrace || t.is_metavar_block() || t.is_keyword(sym::bikeshed)
3433            })
3434            && self.token_uninterpolated_span().at_least_rust_2018()
3435    }
3436
3437    /// Parses an `async move? {...}` or `gen move? {...}` expression.
3438    fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> {
3439        let lo = self.token.span;
3440        let kind = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Async,
    token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
3441            if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Gen,
    token_type: crate::parser::token_type::TokenType::KwGen,
}exp!(Gen)) { CoroutineKind::AsyncGen } else { CoroutineKind::Async }
3442        } else {
3443            if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
                kw: rustc_span::symbol::kw::Gen,
                token_type: crate::parser::token_type::TokenType::KwGen,
            }) {
    ::core::panicking::panic("assertion failed: self.eat_keyword(exp!(Gen))")
};assert!(self.eat_keyword(exp!(Gen)));
3444            CoroutineKind::Gen
3445        };
3446        if kind.is_gen() {
3447            self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3448        }
3449        let capture_clause = self.parse_capture_clause()?;
3450        let decl_span = lo.to(self.prev_token.span);
3451        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3452        let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3453        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3454    }
3455
3456    fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3457        self.is_keyword_ahead(lookahead, &[kw])
3458            && ((
3459                // `async move {`
3460                self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3461                    && self.look_ahead(lookahead + 2, |t| {
3462                        *t == token::OpenBrace || t.is_metavar_block()
3463                    })
3464            ) || (
3465                // `async {`
3466                self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3467            ))
3468    }
3469
3470    pub(super) fn is_async_gen_block(&self) -> bool {
3471        self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3472    }
3473
3474    fn is_likely_struct_lit(&self) -> bool {
3475        // `{ ident, ` and `{ ident: ` cannot start a block.
3476        self.look_ahead(1, |t| t.is_ident())
3477            && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3478    }
3479
3480    fn maybe_parse_struct_expr(
3481        &mut self,
3482        qself: &Option<Box<ast::QSelf>>,
3483        path: &ast::Path,
3484    ) -> Option<PResult<'a, Box<Expr>>> {
3485        let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3486        match (struct_allowed, self.is_likely_struct_lit()) {
3487            // A struct literal isn't expected and one is pretty much assured not to be present. The
3488            // only situation that isn't detected is when a struct with a single field was attempted
3489            // in a place where a struct literal wasn't expected, but regular parser errors apply.
3490            // Happy path.
3491            (false, false) => None,
3492            (true, _) => {
3493                // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for
3494                // any kind of recovery. Happy path.
3495                if let Err(err) = self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
3496                    return Some(Err(err));
3497                }
3498                Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
3499            }
3500            (false, true) => {
3501                // We have something like `match foo { bar,` or `match foo { bar:`, which means the
3502                // user might have meant to write a struct literal as part of the `match`
3503                // discriminant. This is done purely for error recovery.
3504                let snapshot = self.create_snapshot_for_diagnostic();
3505                if let Err(err) = self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
3506                    return Some(Err(err));
3507                }
3508                match self.parse_expr_struct(qself.clone(), path.clone(), false) {
3509                    Ok(expr) => {
3510                        // This is a struct literal, but we don't accept them here.
3511                        self.dcx().emit_err(crate::diagnostics::StructLiteralNotAllowedHere {
3512                            span: expr.span,
3513                            sub: crate::diagnostics::StructLiteralNotAllowedHereSugg {
3514                                left: path.span.shrink_to_lo(),
3515                                right: expr.span.shrink_to_hi(),
3516                            },
3517                        });
3518                        Some(Ok(expr))
3519                    }
3520                    Err(err) => {
3521                        // We couldn't parse a valid struct, rollback and let the parser emit an
3522                        // error elsewhere.
3523                        err.cancel();
3524                        self.restore_snapshot(snapshot);
3525                        None
3526                    }
3527                }
3528            }
3529        }
3530    }
3531
3532    fn maybe_recover_bad_struct_literal_path(
3533        &mut self,
3534        is_underscore_entry_point: bool,
3535    ) -> PResult<'a, Option<Box<Expr>>> {
3536        if self.may_recover()
3537            && self.check_noexpect(&token::OpenBrace)
3538            && (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3539                && self.is_likely_struct_lit())
3540        {
3541            let span = if is_underscore_entry_point {
3542                self.prev_token.span
3543            } else {
3544                self.token.span.shrink_to_lo()
3545            };
3546
3547            self.bump(); // {
3548            let expr = self.parse_expr_struct(
3549                None,
3550                Path::from_ident(Ident::new(kw::Underscore, span)),
3551                false,
3552            )?;
3553
3554            let guar = if is_underscore_entry_point {
3555                self.dcx().emit_err(crate::diagnostics::StructLiteralPlaceholderPath { span })
3556            } else {
3557                self.dcx().emit_err(crate::diagnostics::StructLiteralWithoutPathLate {
3558                    span: expr.span,
3559                    suggestion_span: expr.span.shrink_to_lo(),
3560                })
3561            };
3562
3563            Ok(Some(self.mk_expr_err(expr.span, guar)))
3564        } else {
3565            Ok(None)
3566        }
3567    }
3568
3569    pub(super) fn parse_struct_fields(
3570        &mut self,
3571        pth: ast::Path,
3572        recover: bool,
3573        close: ExpTokenPair,
3574    ) -> PResult<
3575        'a,
3576        (
3577            ThinVec<ExprField>,
3578            ast::StructRest,
3579            Option<ErrorGuaranteed>, /* async blocks are forbidden in Rust 2015 */
3580        ),
3581    > {
3582        let open_span = self.prev_token.span; //{
3583        let mut fields = ThinVec::new();
3584        let mut base = ast::StructRest::None;
3585        let mut recovered_async = None;
3586        let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3587        let in_let = self.restrictions.contains(Restrictions::IN_LET);
3588        let async_block_err = |e: &mut Diag<'_>, span: Span| {
3589            crate::diagnostics::AsyncBlockIn2015 { span }.add_to_diag(e);
3590            crate::diagnostics::HelpUseLatestEdition::new().add_to_diag(e);
3591        };
3592
3593        while self.token != close.tok {
3594            if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::DotDot,
    token_type: crate::parser::token_type::TokenType::DotDot,
}exp!(DotDot)) || self.recover_struct_field_dots(&close.tok) {
3595                let exp_span = self.prev_token.span;
3596                // We permit `.. }` on the left-hand side of a destructuring assignment.
3597                if self.check(close) {
3598                    base = ast::StructRest::Rest(self.prev_token.span);
3599                    break;
3600                }
3601                match self.parse_expr() {
3602                    Ok(e) => base = ast::StructRest::Base(e),
3603                    Err(e) if recover => {
3604                        e.emit();
3605                        self.recover_stmt();
3606                    }
3607                    Err(e) => return Err(e),
3608                }
3609                self.recover_struct_comma_after_dotdot(exp_span);
3610                break;
3611            }
3612
3613            // Peek the field's ident before parsing its expr in order to emit better diagnostics.
3614            let peek = self
3615                .token
3616                .non_reserved_ident()
3617                .filter(|_| self.look_ahead(1, |&tok| tok == token::Colon));
3618
3619            // We still want a field even if its expr didn't parse.
3620            let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3621                peek.map(|ident| {
3622                    let span = ident.span;
3623                    ExprField {
3624                        ident,
3625                        span,
3626                        expr: this.mk_expr_err(span, guar),
3627                        is_shorthand: false,
3628                        attrs: AttrVec::new(),
3629                        id: DUMMY_NODE_ID,
3630                        is_placeholder: false,
3631                    }
3632                })
3633            };
3634
3635            let parsed_field = match self.parse_expr_field() {
3636                Ok(f) => Ok(f),
3637                Err(mut e) => {
3638                    if pth == kw::Async {
3639                        async_block_err(&mut e, pth.span);
3640                    } else {
3641                        e.span_label(pth.span, "while parsing this struct");
3642                    }
3643
3644                    if let Some((ident, _)) = self.token.ident()
3645                        && !self.token.is_reserved_ident()
3646                        && self.look_ahead(1, |t| {
3647                            AssocOp::from_token(t).is_some()
3648                                || #[allow(non_exhaustive_omitted_patterns)] match t.kind {
    token::OpenParen | token::OpenBracket | token::OpenBrace => true,
    _ => false,
}matches!(
3649                                    t.kind,
3650                                    token::OpenParen | token::OpenBracket | token::OpenBrace
3651                                )
3652                                || *t == token::Dot
3653                        })
3654                    {
3655                        // Looks like they tried to write a shorthand, complex expression,
3656                        // E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
3657                        e.span_suggestion_verbose(
3658                            self.token.span.shrink_to_lo(),
3659                            "try naming a field",
3660                            &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: ",),
3661                            Applicability::MaybeIncorrect,
3662                        );
3663                    }
3664                    if in_if_guard && close.token_type == TokenType::CloseBrace {
3665                        return Err(e);
3666                    }
3667
3668                    if !recover {
3669                        return Err(e);
3670                    }
3671
3672                    if in_let {
3673                        // Better diagnostic for `foo { return 42; };`
3674                        // We've consumed `foo {` already
3675                        let mut snapshot = self.create_snapshot_for_diagnostic();
3676                        let might_be_stmt = snapshot.token.is_keyword(kw::Return);
3677                        snapshot.consume_block(
3678                            crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace),
3679                            crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace),
3680                            super::diagnostics::ConsumeClosingDelim::Yes,
3681                        ); //consume to the end of the block, including `}`
3682
3683                        // make sure the block is at the end by eating a `;`,
3684                        // we shouldn't report such diagnostic for `let a = foo{return 43;}+bar;`
3685                        // also skip the suggestion if the span cross macro boundaries
3686                        if might_be_stmt
3687                            && snapshot.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Semi,
    token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi))
3688                            && pth.span.ctxt() == open_span.ctxt()
3689                        {
3690                            let span = pth.span.between(open_span);
3691                            e.subdiagnostic(crate::diagnostics::MissingElseInLet { span });
3692                            self.restore_snapshot(snapshot);
3693                            return Err(e);
3694                        }
3695                    }
3696                    let guar = e.emit_err();
3697                    if pth == kw::Async {
3698                        recovered_async = Some(guar);
3699                    }
3700
3701                    // If we encountered an error which we are recovering from, treat the struct
3702                    // as if it has a `..` in it, because we don’t know what fields the user
3703                    // might have *intended* it to have.
3704                    //
3705                    // This assignment will be overwritten if we actually parse a `..` later.
3706                    //
3707                    // (Note that this code is duplicated between here and below in comma parsing.
3708                    base = ast::StructRest::NoneWithError(guar);
3709
3710                    // If the next token is a comma, then try to parse
3711                    // what comes next as additional fields, rather than
3712                    // bailing out until next `}`.
3713                    if self.token != token::Comma {
3714                        self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3715                        if self.token != token::Comma {
3716                            break;
3717                        }
3718                    }
3719
3720                    Err(guar)
3721                }
3722            };
3723
3724            let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
3725            // A shorthand field can be turned into a full field with `:`.
3726            // We should point this out.
3727            self.check_or_expected(!is_shorthand, TokenType::Colon);
3728
3729            match self.expect_one_of(&[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)], &[close]) {
3730                Ok(_) => {
3731                    if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
3732                    {
3733                        // Only include the field if there's no parse error for the field name.
3734                        fields.push(f);
3735                    }
3736                }
3737                Err(mut e) => {
3738                    if pth == kw::Async {
3739                        async_block_err(&mut e, pth.span);
3740                    } else {
3741                        e.span_label(pth.span, "while parsing this struct");
3742                        if peek.is_some() {
3743                            e.span_suggestion(
3744                                self.prev_token.span.shrink_to_hi(),
3745                                "try adding a comma",
3746                                ",",
3747                                Applicability::MachineApplicable,
3748                            );
3749                        }
3750                    }
3751                    if !recover {
3752                        return Err(e);
3753                    }
3754                    let guar = e.emit_err();
3755                    if pth == kw::Async {
3756                        recovered_async = Some(guar);
3757                    } else if let Some(f) = field_ident(self, guar) {
3758                        fields.push(f);
3759                    }
3760
3761                    // See comment above on this same assignment inside of field parsing.
3762                    base = ast::StructRest::NoneWithError(guar);
3763
3764                    self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3765                    let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3766                }
3767            }
3768        }
3769        Ok((fields, base, recovered_async))
3770    }
3771
3772    /// Precondition: already parsed the '{'.
3773    pub(super) fn parse_expr_struct(
3774        &mut self,
3775        qself: Option<Box<ast::QSelf>>,
3776        pth: ast::Path,
3777        recover: bool,
3778    ) -> PResult<'a, Box<Expr>> {
3779        let lo = pth.span;
3780        let (fields, base, recovered_async) =
3781            self.parse_struct_fields(pth.clone(), recover, crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
3782        let span = lo.to(self.token.span);
3783        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
3784        let expr = if let Some(guar) = recovered_async {
3785            ExprKind::Err(guar)
3786        } else {
3787            ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base }))
3788        };
3789        Ok(self.mk_expr(span, expr))
3790    }
3791
3792    fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
3793        if self.token != token::Comma {
3794            return;
3795        }
3796        self.dcx().emit_err(crate::diagnostics::CommaAfterBaseStruct {
3797            span: span.to(self.prev_token.span),
3798            comma: self.token.span,
3799        });
3800        self.recover_stmt();
3801    }
3802
3803    fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
3804        if !self.look_ahead(1, |t| t == close) && self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::DotDotDot,
    token_type: crate::parser::token_type::TokenType::DotDotDot,
}exp!(DotDotDot)) {
3805            // recover from typo of `...`, suggest `..`
3806            let span = self.prev_token.span;
3807            self.dcx()
3808                .emit_err(crate::diagnostics::MissingDotDot { token_span: span, sugg_span: span });
3809            return true;
3810        }
3811        false
3812    }
3813
3814    /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
3815    fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
3816        // Convert `label` -> `'label`,
3817        // so that nameres doesn't complain about non-existing label
3818        let label = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\'{0}", ident.name))
    })format!("'{}", ident.name);
3819        let ident = Ident::new(Symbol::intern(&label), ident.span);
3820
3821        self.dcx().emit_err(crate::diagnostics::ExpectedLabelFoundIdent {
3822            span: ident.span,
3823            start: ident.span.shrink_to_lo(),
3824        });
3825
3826        Label { ident }
3827    }
3828
3829    /// Parses `ident (COLON expr)?`.
3830    fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
3831        let attrs = self.parse_outer_attributes()?;
3832        self.recover_vcs_conflict_marker();
3833        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3834            // Check if a colon exists one ahead. This means we're parsing a fieldname.
3835            let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
3836            // Proactively check whether parsing the field will be incorrect.
3837            let is_wrong = this.token.is_non_reserved_ident()
3838                && !this.look_ahead(1, |t| {
3839                    t == &token::Colon
3840                        || t == &token::Eq
3841                        || t == &token::Comma
3842                        || t == &token::CloseBrace
3843                        || t == &token::CloseParen
3844                });
3845            if is_wrong {
3846                return Err(this.dcx().create_err(crate::diagnostics::ExpectedStructField {
3847                    span: this.look_ahead(1, |t| t.span),
3848                    ident_span: this.token.span,
3849                    token: pprust::token_to_string(&this.look_ahead(1, |t| *t)),
3850                }));
3851            }
3852            let (ident, expr, span) = if is_shorthand {
3853                // Mimic `x: x` for the `x` field shorthand.
3854                let ident = this.parse_ident_common(false)?;
3855                let path = ast::Path::from_ident(ident);
3856                (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)), ident.span)
3857            } else {
3858                let ident = this.parse_field_name()?;
3859                let span = ident.span.to(this.token.span);
3860                this.error_on_eq_field_init(ident);
3861                this.bump(); // `:`
3862                let expr = this.parse_expr()?;
3863                let span = span.to(expr.span);
3864                (ident, expr, span)
3865            };
3866
3867            Ok((
3868                ast::ExprField {
3869                    ident,
3870                    span,
3871                    expr,
3872                    is_shorthand,
3873                    attrs,
3874                    id: DUMMY_NODE_ID,
3875                    is_placeholder: false,
3876                },
3877                Trailing::from(this.token == token::Comma),
3878                UsePreAttrPos::No,
3879            ))
3880        })
3881    }
3882
3883    /// Check for `=`. This means the source incorrectly attempts to
3884    /// initialize a field with an eq rather than a colon.
3885    fn error_on_eq_field_init(&self, field_name: Ident) {
3886        if self.token != token::Eq {
3887            return;
3888        }
3889
3890        self.dcx().emit_err(crate::diagnostics::EqFieldInit {
3891            span: self.token.span,
3892            eq: field_name.span.shrink_to_hi().to(self.token.span),
3893        });
3894    }
3895
3896    fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
3897        ExprKind::AssignOp(assign_op, lhs, rhs)
3898    }
3899
3900    fn mk_range(
3901        &mut self,
3902        start: Option<Box<Expr>>,
3903        end: Option<Box<Expr>>,
3904        limits: RangeLimits,
3905    ) -> ExprKind {
3906        if end.is_none() && limits == RangeLimits::Closed {
3907            let guar = self.inclusive_range_with_incorrect_end();
3908            ExprKind::Err(guar)
3909        } else {
3910            ExprKind::Range(start, end, limits)
3911        }
3912    }
3913
3914    fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind {
3915        ExprKind::Unary(unop, expr)
3916    }
3917
3918    fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
3919        ExprKind::Binary(binop, lhs, rhs)
3920    }
3921
3922    fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind {
3923        ExprKind::Index(expr, idx, brackets_span)
3924    }
3925
3926    fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind {
3927        ExprKind::Call(f, args)
3928    }
3929
3930    fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
3931        let span = lo.to(self.prev_token.span);
3932        let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
3933        self.recover_from_await_method_call();
3934        await_expr
3935    }
3936
3937    fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
3938        let span = lo.to(self.prev_token.span);
3939        let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
3940        self.recover_from_use();
3941        use_expr
3942    }
3943
3944    pub(crate) fn mk_expr_with_attrs(
3945        &self,
3946        span: Span,
3947        kind: ExprKind,
3948        attrs: AttrVec,
3949    ) -> Box<Expr> {
3950        Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
3951    }
3952
3953    pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> {
3954        self.mk_expr_with_attrs(span, kind, AttrVec::new())
3955    }
3956
3957    pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> {
3958        self.mk_expr(span, ExprKind::Err(guar))
3959    }
3960
3961    pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
3962        self.mk_expr(span, ExprKind::Tup(Default::default()))
3963    }
3964
3965    pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
3966        self.mk_expr(
3967            span,
3968            ast::ExprKind::Closure(Box::new(ast::Closure {
3969                binder: rustc_ast::ClosureBinder::NotPresent,
3970                constness: rustc_ast::Const::No,
3971                movability: rustc_ast::Movability::Movable,
3972                capture_clause: rustc_ast::CaptureBy::Ref,
3973                coroutine_marker: None,
3974                fn_decl: Box::new(rustc_ast::FnDecl {
3975                    inputs: Default::default(),
3976                    output: rustc_ast::FnRetTy::Default(span),
3977                }),
3978                fn_arg_span: span,
3979                fn_decl_span: span,
3980                body,
3981            })),
3982        )
3983    }
3984
3985    /// Create expression span ensuring the span of the parent node
3986    /// is larger than the span of lhs and rhs, including the attributes.
3987    fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
3988        lhs.attrs
3989            .iter()
3990            .find(|a| a.style == AttrStyle::Outer)
3991            .map_or(lhs_span, |a| a.span)
3992            .to(op_span)
3993            .to(rhs_span)
3994    }
3995
3996    fn collect_tokens_for_expr(
3997        &mut self,
3998        attrs: AttrWrapper,
3999        f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>,
4000    ) -> PResult<'a, Box<Expr>> {
4001        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4002            let res = f(this, attrs)?;
4003            let trailing = Trailing::from(
4004                this.restrictions.contains(Restrictions::STMT_EXPR)
4005                     && this.token == token::Semi
4006                // FIXME: pass an additional condition through from the place
4007                // where we know we need a comma, rather than assuming that
4008                // `#[attr] expr,` always captures a trailing comma.
4009                || this.token == token::Comma,
4010            );
4011            Ok((res, trailing, UsePreAttrPos::No))
4012        })
4013    }
4014}
4015
4016/// Could this lifetime/label be an unclosed char literal? For example, `'a`
4017/// could be, but `'abc` could not.
4018pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4019    ident.name.as_str().starts_with('\'')
4020        && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4021}
4022
4023/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
4024/// 2024 and later). In case of edition dependence, specify the currently present edition.
4025pub enum LetChainsPolicy {
4026    AlwaysAllowed,
4027    EditionDependent { current_edition: Edition },
4028}
4029
4030/// Visitor to check for invalid use of `ExprKind::Let` that can't
4031/// easily be caught in parsing. For example:
4032///
4033/// ```rust,ignore (example)
4034/// // Only know that the let isn't allowed once the `||` token is reached
4035/// if let Some(x) = y || true {}
4036/// // Only know that the let isn't allowed once the second `=` token is reached.
4037/// if let Some(x) = y && z = 1 {}
4038/// ```
4039struct CondChecker<'a> {
4040    parser: &'a Parser<'a>,
4041    let_chains_policy: LetChainsPolicy,
4042    depth: u32,
4043    forbid_let_reason: Option<crate::diagnostics::ForbiddenLetReason>,
4044    missing_let: Option<crate::diagnostics::MaybeMissingLet>,
4045    comparison: Option<crate::diagnostics::MaybeComparison>,
4046    found_incorrect_let_chain: Option<ErrorGuaranteed>,
4047}
4048
4049impl<'a> CondChecker<'a> {
4050    fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4051        CondChecker {
4052            parser,
4053            forbid_let_reason: None,
4054            missing_let: None,
4055            comparison: None,
4056            let_chains_policy,
4057            found_incorrect_let_chain: None,
4058            depth: 0,
4059        }
4060    }
4061}
4062
4063impl MutVisitor for CondChecker<'_> {
4064    fn visit_expr(&mut self, e: &mut Expr) {
4065        self.depth += 1;
4066
4067        let span = e.span;
4068        match e.kind {
4069            ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4070                if let Some(reason) = self.forbid_let_reason {
4071                    let error = match reason {
4072                        crate::diagnostics::ForbiddenLetReason::NotSupportedOr(or_span) => self
4073                            .parser
4074                            .dcx()
4075                            .emit_err(crate::diagnostics::OrInLetChain { span: or_span }),
4076                        _ => {
4077                            let guar = self.parser.dcx().emit_err(
4078                                crate::diagnostics::ExpectedExpressionFoundLet {
4079                                    span,
4080                                    reason,
4081                                    missing_let: self.missing_let,
4082                                    comparison: self.comparison,
4083                                },
4084                            );
4085                            if let Some(_) = self.missing_let {
4086                                self.found_incorrect_let_chain = Some(guar);
4087                            }
4088                            guar
4089                        }
4090                    };
4091                    *recovered = Recovered::Yes(error);
4092                } else if self.depth > 1 {
4093                    // Top level `let` is always allowed; only gate chains
4094                    match self.let_chains_policy {
4095                        LetChainsPolicy::AlwaysAllowed => (),
4096                        LetChainsPolicy::EditionDependent { current_edition } => {
4097                            if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4098                                self.parser
4099                                    .dcx()
4100                                    .emit_err(crate::diagnostics::LetChainPre2024 { span });
4101                            }
4102                        }
4103                    }
4104                }
4105            }
4106            ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4107                mut_visit::walk_expr(self, e);
4108            }
4109            ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4110                if let None | Some(crate::diagnostics::ForbiddenLetReason::NotSupportedOr(_)) =
4111                    self.forbid_let_reason =>
4112            {
4113                let forbid_let_reason = self.forbid_let_reason;
4114                self.forbid_let_reason =
4115                    Some(crate::diagnostics::ForbiddenLetReason::NotSupportedOr(or_span));
4116                mut_visit::walk_expr(self, e);
4117                self.forbid_let_reason = forbid_let_reason;
4118            }
4119            ExprKind::Paren(ref inner)
4120                if let None
4121                | Some(crate::diagnostics::ForbiddenLetReason::NotSupportedParentheses(_)) =
4122                    self.forbid_let_reason =>
4123            {
4124                let forbid_let_reason = self.forbid_let_reason;
4125                self.forbid_let_reason = Some(
4126                    crate::diagnostics::ForbiddenLetReason::NotSupportedParentheses(inner.span),
4127                );
4128                mut_visit::walk_expr(self, e);
4129                self.forbid_let_reason = forbid_let_reason;
4130            }
4131            ExprKind::Assign(ref lhs, ref rhs, span) => {
4132                if let ExprKind::Call(_, _) = &lhs.kind {
4133                    fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4134                        fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4135                            match &e.kind {
4136                                ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
4137                                ExprKind::Path(_, path) => Some((depth, path)),
4138                                _ => None,
4139                            }
4140                        }
4141
4142                        inner(e, 0)
4143                    }
4144
4145                    if let Some((depth, path)) = get_path_from_rhs(rhs) {
4146                        // For cases like if Some(_) = x && let Some(_) = y && let Some(_) = z
4147                        // This return let Some(_) = y expression
4148                        fn find_let_some(expr: &Expr) -> Option<&Expr> {
4149                            match &expr.kind {
4150                                ExprKind::Let(..) => Some(expr),
4151
4152                                ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
4153                                    find_let_some(lhs).or_else(|| find_let_some(rhs))
4154                                }
4155
4156                                _ => None,
4157                            }
4158                        }
4159
4160                        let expr_span = lhs.span.to(path.span);
4161
4162                        if let Some(later_rhs) = find_let_some(rhs)
4163                            && depth > 0
4164                        {
4165                            let guar = self.parser.dcx().emit_err(
4166                                crate::diagnostics::LetChainMissingLet {
4167                                    span: lhs.span,
4168                                    label_span: expr_span,
4169                                    rhs_span: later_rhs.span,
4170                                    sug_span: lhs.span.shrink_to_lo(),
4171                                },
4172                            );
4173
4174                            self.found_incorrect_let_chain = Some(guar);
4175                        }
4176                    }
4177                }
4178
4179                let forbid_let_reason = self.forbid_let_reason;
4180                self.forbid_let_reason =
4181                    Some(crate::diagnostics::ForbiddenLetReason::OtherForbidden);
4182                let missing_let = self.missing_let;
4183                if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4184                    && let ExprKind::Path(_, _)
4185                    | ExprKind::Struct(_)
4186                    | ExprKind::Call(_, _)
4187                    | ExprKind::Array(_) = rhs.kind
4188                {
4189                    self.missing_let =
4190                        Some(crate::diagnostics::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4191                }
4192                let comparison = self.comparison;
4193                self.comparison =
4194                    Some(crate::diagnostics::MaybeComparison { span: span.shrink_to_hi() });
4195                mut_visit::walk_expr(self, e);
4196                self.forbid_let_reason = forbid_let_reason;
4197                self.missing_let = missing_let;
4198                self.comparison = comparison;
4199            }
4200            ExprKind::Unary(_, _)
4201            | ExprKind::Await(_, _)
4202            | ExprKind::Move(_, _)
4203            | ExprKind::Use(_, _)
4204            | ExprKind::AssignOp(_, _, _)
4205            | ExprKind::Range(_, _, _)
4206            | ExprKind::Try(_)
4207            | ExprKind::AddrOf(_, _, _)
4208            | ExprKind::Binary(_, _, _)
4209            | ExprKind::Field(_, _)
4210            | ExprKind::Index(_, _, _)
4211            | ExprKind::Call(_, _)
4212            | ExprKind::MethodCall(_)
4213            | ExprKind::Tup(_)
4214            | ExprKind::Paren(_) => {
4215                let forbid_let_reason = self.forbid_let_reason;
4216                self.forbid_let_reason =
4217                    Some(crate::diagnostics::ForbiddenLetReason::OtherForbidden);
4218                mut_visit::walk_expr(self, e);
4219                self.forbid_let_reason = forbid_let_reason;
4220            }
4221            ExprKind::Cast(ref mut op, _)
4222            | ExprKind::Type(ref mut op, _)
4223            | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4224                let forbid_let_reason = self.forbid_let_reason;
4225                self.forbid_let_reason =
4226                    Some(crate::diagnostics::ForbiddenLetReason::OtherForbidden);
4227                self.visit_expr(op);
4228                self.forbid_let_reason = forbid_let_reason;
4229            }
4230            ExprKind::Let(_, _, _, Recovered::Yes(_))
4231            | ExprKind::Array(_)
4232            | ExprKind::ConstBlock(_)
4233            | ExprKind::Lit(_)
4234            | ExprKind::If(_, _, _)
4235            | ExprKind::While(_, _, _)
4236            | ExprKind::ForLoop { .. }
4237            | ExprKind::Loop(_, _, _)
4238            | ExprKind::Match(_, _, _)
4239            | ExprKind::Closure(_)
4240            | ExprKind::Block(_, _)
4241            | ExprKind::Gen(_, _, _, _)
4242            | ExprKind::TryBlock(_, _)
4243            | ExprKind::Underscore
4244            | ExprKind::Path(_, _)
4245            | ExprKind::Break(_, _)
4246            | ExprKind::Continue(_)
4247            | ExprKind::Ret(_)
4248            | ExprKind::InlineAsm(_)
4249            | ExprKind::OffsetOf(_, _)
4250            | ExprKind::MacCall(_)
4251            | ExprKind::Struct(_)
4252            | ExprKind::Repeat(_, _)
4253            | ExprKind::Yield(_)
4254            | ExprKind::Yeet(_)
4255            | ExprKind::Become(_)
4256            | ExprKind::IncludedBytes(_)
4257            | ExprKind::FormatArgs(_)
4258            | ExprKind::Err(_)
4259            | ExprKind::GcaMacro(_)
4260            | ExprKind::Dummy => {
4261                // These would forbid any let expressions they contain already.
4262            }
4263        }
4264        self.depth -= 1;
4265    }
4266}