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::IdentIsRaw;
8use ast::{CoroutineKind, ForLoopKind, GenBlockKind, 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, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
17    FnRetTy, ForLoop, Guard, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind,
18    Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
19};
20use rustc_ast_pretty::pprust;
21use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
22use rustc_literal_escaper::unescape_char;
23use rustc_session::diagnostics::report_lit_error;
24use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
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::diagnostics::ExprParenthesesNeeded;
38use crate::{diagnostics, exp, maybe_recover_from_interpolated_ty_qpath};
39
40#[derive(#[automatically_derived]
impl ::core::fmt::Debug for DestructuredFloat {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            DestructuredFloat::Single(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Single",
                    __self_0, &__self_1),
            DestructuredFloat::TrailingDot(__self_0, __self_1, __self_2) =>
                ::core::fmt::Formatter::debug_tuple_field3_finish(f,
                    "TrailingDot", __self_0, __self_1, &__self_2),
            DestructuredFloat::MiddleDot(__self_0, __self_1, __self_2,
                __self_3, __self_4) =>
                ::core::fmt::Formatter::debug_tuple_field5_finish(f,
                    "MiddleDot", __self_0, __self_1, __self_2, __self_3,
                    &__self_4),
            DestructuredFloat::Error =>
                ::core::fmt::Formatter::write_str(f, "Error"),
        }
    }
}Debug)]
41pub(super) enum DestructuredFloat {
42    /// 1e2
43    Single(Symbol, Span),
44    /// 1.
45    TrailingDot(Symbol, Span, Span),
46    /// 1.2 | 1.2e3
47    MiddleDot(Symbol, Span, Span, Symbol, Span),
48    /// Invalid
49    Error,
50}
51
52impl<'a> Parser<'a> {
53    /// Parses an expression.
54    #[inline]
55    pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> {
56        self.current_closure.take();
57        self.parse_expr_res(Restrictions::empty())
58    }
59
60    /// Parses an expression, forcing tokens to be collected.
61    pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {
62        self.current_closure.take();
63
64        // If the expression is associative (e.g. `1 + 2`), then any preceding
65        // outer attribute actually belongs to the first inner sub-expression.
66        // In which case we must use the pre-attr pos to include the attribute
67        // in the collected tokens for the outer expression.
68        let pre_attr_pos = self.collect_pos();
69        let attrs = self.parse_outer_attributes()?;
70        self.collect_tokens(
71            Some(pre_attr_pos),
72            AttrWrapper::empty(),
73            ForceCollect::Yes,
74            |this, _empty_attrs| {
75                let (expr, is_assoc) =
76                    this.parse_expr_res_after_attrs(Restrictions::empty(), attrs)?;
77                let use_pre_attr_pos =
78                    if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
79                Ok((expr, Trailing::No, use_pre_attr_pos))
80            },
81        )
82    }
83
84    pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
85        self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
86    }
87
88    fn parse_expr_catch_underscore(
89        &mut self,
90        restrictions: Restrictions,
91    ) -> PResult<'a, Box<Expr>> {
92        match self.parse_expr_res(restrictions) {
93            Ok(expr) => Ok(expr),
94            Err(err) => match self.token.ident() {
95                Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No))
96                    if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
97                {
98                    // Special-case handling of `foo(_, _, _)`
99                    let guar = err.emit();
100                    self.bump();
101                    Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar)))
102                }
103                _ => Err(err),
104            },
105        }
106    }
107
108    /// Parses a sequence of expressions delimited by parentheses.
109    fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {
110        self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore(Restrictions::empty()))
111            .map(|(r, _)| r)
112    }
113
114    /// Parses an expression, subject to the given restrictions.
115    #[inline]
116    pub(super) fn parse_expr_res(&mut self, r: Restrictions) -> PResult<'a, Box<Expr>> {
117        let attrs = self.parse_outer_attributes()?;
118        self.parse_expr_res_after_attrs(r, attrs).map(|(expr, _)| expr)
119    }
120
121    /// Same as `parse_expr_res`, but with attributes already pre-parsed.
122    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
123    /// followed by a subexpression (e.g. `1 + 2`).
124    #[inline]
125    pub(super) fn parse_expr_res_after_attrs(
126        &mut self,
127        r: Restrictions,
128        attrs: AttrWrapper,
129    ) -> PResult<'a, (Box<Expr>, bool)> {
130        self.with_res(r, |this| this.parse_expr_assoc_after_attrs(Bound::Unbounded, attrs))
131    }
132
133    /// Parses an associative expression with operators of at least `min_prec` precedence.
134    pub(super) fn parse_expr_assoc(
135        &mut self,
136        min_prec: Bound<ExprPrecedence>,
137    ) -> PResult<'a, Box<Expr>> {
138        let attrs = self.parse_outer_attributes()?;
139        self.parse_expr_assoc_after_attrs(min_prec, attrs).map(|(expr, _)| expr)
140    }
141
142    /// Same as `parse_expr_assoc`, but with attributes already pre-parsed.
143    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
144    /// followed by a subexpression (e.g. `1 + 2`).
145    pub(super) fn parse_expr_assoc_after_attrs(
146        &mut self,
147        min_prec: Bound<ExprPrecedence>,
148        attrs: AttrWrapper,
149    ) -> PResult<'a, (Box<Expr>, bool)> {
150        let lhs = if self.token.is_range_separator() {
151            return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
152        } else {
153            self.parse_expr_prefix(attrs)?
154        };
155        self.parse_expr_assoc_rest(min_prec, false, lhs)
156    }
157
158    /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
159    /// of at least `min_prec` precedence. The `bool` in the return value indicates if something
160    /// was actually parsed.
161    pub(super) fn parse_expr_assoc_rest(
162        &mut self,
163        min_prec: Bound<ExprPrecedence>,
164        starts_stmt: bool,
165        mut lhs: Box<Expr>,
166    ) -> PResult<'a, (Box<Expr>, bool)> {
167        let mut parsed_something = false;
168        if !self.should_continue_as_assoc_expr(&lhs) {
169            return Ok((lhs, parsed_something));
170        }
171
172        self.expected_token_types.insert(TokenType::Operator);
173        while let Some(op) = self.check_assoc_op() {
174            let lhs_span = self.interpolated_or_expr_span(&lhs);
175            let cur_op_span = self.token.span;
176            let restrictions = if op.node.is_assign_like() {
177                self.restrictions & Restrictions::NO_STRUCT_LITERAL
178            } else {
179                self.restrictions
180            };
181            let prec = op.node.precedence();
182            if match min_prec {
183                Bound::Included(min_prec) => prec < min_prec,
184                Bound::Excluded(min_prec) => prec <= min_prec,
185                Bound::Unbounded => false,
186            } {
187                break;
188            }
189            // Check for deprecated `...` syntax
190            if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {
191                self.err_dotdotdot_syntax(self.token.span);
192            }
193
194            if self.token == token::LArrow {
195                self.err_larrow_operator(self.token.span);
196            }
197
198            parsed_something = true;
199            self.bump();
200            if op.node.is_comparison() {
201                if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
202                    return Ok((expr, parsed_something));
203                }
204            }
205
206            // Look for JS' `===` and `!==` and recover
207            if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
208                && self.token == token::Eq
209                && self.prev_token.span.hi() == self.token.span.lo()
210            {
211                let sp = op.span.to(self.token.span);
212                let sugg = bop.as_str().into();
213                let invalid = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}=", sugg))
    })format!("{sugg}=");
214                self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
215                    span: sp,
216                    invalid: invalid.clone(),
217                    sub: diagnostics::InvalidComparisonOperatorSub::Correctable {
218                        span: sp,
219                        invalid,
220                        correct: sugg,
221                    },
222                });
223                self.bump();
224            }
225
226            // Look for PHP's `<>` and recover
227            if op.node == AssocOp::Binary(BinOpKind::Lt)
228                && self.token == token::Gt
229                && self.prev_token.span.hi() == self.token.span.lo()
230            {
231                let sp = op.span.to(self.token.span);
232                self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
233                    span: sp,
234                    invalid: "<>".into(),
235                    sub: diagnostics::InvalidComparisonOperatorSub::Correctable {
236                        span: sp,
237                        invalid: "<>".into(),
238                        correct: "!=".into(),
239                    },
240                });
241                self.bump();
242            }
243
244            // Look for C++'s `<=>` and recover
245            if op.node == AssocOp::Binary(BinOpKind::Le)
246                && self.token == token::Gt
247                && self.prev_token.span.hi() == self.token.span.lo()
248            {
249                let sp = op.span.to(self.token.span);
250                self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
251                    span: sp,
252                    invalid: "<=>".into(),
253                    sub: diagnostics::InvalidComparisonOperatorSub::Spaceship(sp),
254                });
255                self.bump();
256            }
257
258            if self.prev_token == token::Plus
259                && self.token == token::Plus
260                && self.prev_token.span.between(self.token.span).is_empty()
261            {
262                let op_span = self.prev_token.span.to(self.token.span);
263                // Eat the second `+`
264                self.bump();
265                lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
266                continue;
267            }
268
269            if self.prev_token == token::Minus
270                && self.token == token::Minus
271                && self.prev_token.span.between(self.token.span).is_empty()
272                && !self.look_ahead(1, |tok| tok.can_begin_expr())
273            {
274                let op_span = self.prev_token.span.to(self.token.span);
275                // Eat the second `-`
276                self.bump();
277                lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?;
278                continue;
279            }
280
281            let op_span = op.span;
282            let op = op.node;
283            // Special cases:
284            if op == AssocOp::Cast {
285                lhs = self.parse_assoc_op_cast(lhs, lhs_span, op_span, ExprKind::Cast)?;
286                continue;
287            } else if let AssocOp::Range(limits) = op {
288                // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
289                // generalise it to the Fixity::None code.
290                lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;
291                break;
292            }
293
294            let min_prec = match op.fixity() {
295                Fixity::Right => Bound::Included(prec),
296                Fixity::Left | Fixity::None => Bound::Excluded(prec),
297            };
298            let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
299                this.parse_expr_assoc(min_prec)
300            })?;
301
302            let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
303            lhs = match op {
304                AssocOp::Binary(ast_op) => {
305                    let binary = self.mk_binary(respan(cur_op_span, ast_op), lhs, rhs);
306                    self.mk_expr(span, binary)
307                }
308                AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
309                AssocOp::AssignOp(aop) => {
310                    let aopexpr = self.mk_assign_op(respan(cur_op_span, aop), lhs, rhs);
311                    self.mk_expr(span, aopexpr)
312                }
313                AssocOp::Cast | AssocOp::Range(_) => {
314                    self.dcx().span_bug(span, "AssocOp should have been handled by special case")
315                }
316            };
317        }
318
319        Ok((lhs, parsed_something))
320    }
321
322    fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
323        match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
324            // Semi-statement forms are odd:
325            // See https://github.com/rust-lang/rust/issues/29071
326            (true, None) => false,
327            (false, _) => true, // Continue parsing the expression.
328            // An exhaustive check is done in the following block, but these are checked first
329            // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
330            // want to keep their span info to improve diagnostics in these cases in a later stage.
331            (true, Some(AssocOp::Binary(
332                BinOpKind::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
333                BinOpKind::Sub | // `{ 42 } -5`
334                BinOpKind::Add | // `{ 42 } + 42` (unary plus)
335                BinOpKind::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
336                BinOpKind::Or | // `{ 42 } || 42` ("logical or" or closure)
337                BinOpKind::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42`
338            ))) => {
339                // These cases are ambiguous and can't be identified in the parser alone.
340                //
341                // Bitwise AND is left out because guessing intent is hard. We can make
342                // suggestions based on the assumption that double-refs are rarely intentional,
343                // and closures are distinct enough that they don't get mixed up with their
344                // return value.
345                let sp = self.psess.source_map().start_point(self.token.span);
346                self.psess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
347                false
348            }
349            (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,
350            (true, Some(_)) => {
351                self.error_found_expr_would_be_stmt(lhs);
352                true
353            }
354        }
355    }
356
357    /// We've found an expression that would be parsed as a statement,
358    /// but the next token implies this should be parsed as an expression.
359    /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
360    fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
361        self.dcx().emit_err(diagnostics::FoundExprWouldBeStmt {
362            span: self.token.span,
363            token: pprust::token_to_string(&self.token),
364            suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
365        });
366    }
367
368    /// Possibly translate the current token to an associative operator.
369    /// The method does not advance the current token.
370    ///
371    /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
372    pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
373        let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
374            // When parsing const expressions, stop parsing when encountering `>`.
375            (
376                Some(
377                    AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
378                    | AssocOp::AssignOp(AssignOpKind::ShrAssign),
379                ),
380                _,
381            ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
382                return None;
383            }
384            // When recovering patterns as expressions, stop parsing when encountering an
385            // assignment `=`, an alternative `|`, or a range `..`.
386            (
387                Some(
388                    AssocOp::Assign
389                    | AssocOp::AssignOp(_)
390                    | AssocOp::Binary(BinOpKind::BitOr)
391                    | AssocOp::Range(_),
392                ),
393                _,
394            ) if self.restrictions.contains(Restrictions::IS_PAT) => {
395                return None;
396            }
397            (Some(op), _) => (op, self.token.span),
398            (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No)))
399                if self.may_recover() =>
400            {
401                self.dcx().emit_err(diagnostics::InvalidLogicalOperator {
402                    span: self.token.span,
403                    incorrect: "and".into(),
404                    sub: diagnostics::InvalidLogicalOperatorSub::Conjunction(self.token.span),
405                });
406                (AssocOp::Binary(BinOpKind::And), span)
407            }
408            (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
409                self.dcx().emit_err(diagnostics::InvalidLogicalOperator {
410                    span: self.token.span,
411                    incorrect: "or".into(),
412                    sub: diagnostics::InvalidLogicalOperatorSub::Disjunction(self.token.span),
413                });
414                (AssocOp::Binary(BinOpKind::Or), span)
415            }
416            _ => return None,
417        };
418        Some(respan(span, op))
419    }
420
421    /// Checks if this expression is a successfully parsed statement.
422    fn expr_is_complete(&self, e: &Expr) -> bool {
423        self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
424    }
425
426    /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
427    /// The other two variants are handled in `parse_prefix_range_expr` below.
428    fn parse_expr_range(
429        &mut self,
430        prec: ExprPrecedence,
431        lhs: Box<Expr>,
432        limits: RangeLimits,
433        cur_op_span: Span,
434    ) -> PResult<'a, Box<Expr>> {
435        let rhs = if self.is_at_start_of_range_notation_rhs() {
436            let maybe_lt = self.token;
437            Some(
438                self.parse_expr_assoc(Bound::Excluded(prec))
439                    .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
440            )
441        } else {
442            None
443        };
444        let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
445        let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);
446        let range = self.mk_range(Some(lhs), rhs, limits);
447        Ok(self.mk_expr(span, range))
448    }
449
450    fn is_at_start_of_range_notation_rhs(&self) -> bool {
451        if self.token.can_begin_expr() {
452            // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
453            if self.token == token::OpenBrace {
454                return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
455            }
456            true
457        } else {
458            false
459        }
460    }
461
462    /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
463    fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
464        if !attrs.is_empty() {
465            let err = diagnostics::DotDotRangeAttribute { span: self.token.span };
466            self.dcx().emit_err(err);
467        }
468
469        // Check for deprecated `...` syntax.
470        if self.token == token::DotDotDot {
471            self.err_dotdotdot_syntax(self.token.span);
472        }
473
474        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!(
475            self.token.is_range_separator(),
476            "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
477            self.token
478        );
479
480        let limits = match self.token.kind {
481            token::DotDot => RangeLimits::HalfOpen,
482            _ => RangeLimits::Closed,
483        };
484        let op = AssocOp::from_token(&self.token);
485        self.collect_tokens_for_expr(AttrWrapper::empty(), |this, _empty_attrs| {
486            let lo = this.token.span;
487            let maybe_lt = this.look_ahead(1, |t| t.clone());
488            this.bump();
489            let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
490                // RHS must be parsed with more associativity than the dots.
491                this.parse_expr_assoc(Bound::Excluded(op.unwrap().precedence()))
492                    .map(|expr| (lo.to(expr.span), Some(expr)))
493                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
494            } else {
495                (lo, None)
496            };
497            let range = this.mk_range(None, opt_end, limits);
498            Ok(this.mk_expr(span, range))
499        })
500    }
501
502    /// Parses a prefix-unary-operator expr.
503    fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
504        let lo = self.token.span;
505
506        macro_rules! make_it {
507            ($this:ident, $attrs:expr, |this, _| $body:expr) => {
508                $this.collect_tokens_for_expr($attrs, |$this, attrs| {
509                    let (hi, ex) = $body?;
510                    Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
511                })
512            };
513        }
514
515        let this = self;
516
517        // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
518        match this.token.uninterpolate().kind {
519            // `!expr`
520            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)),
521            // `~expr`
522            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)),
523            // `-expr`
524            token::Minus => {
525                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))
526            }
527            // `*expr`
528            token::Star => {
529                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))
530            }
531            // `&expr` and `&&expr`
532            token::And | token::AndAnd => {
533                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))
534            }
535            // `+lit`
536            token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
537                let mut err = diagnostics::LeadingPlusNotSupported {
538                    span: lo,
539                    remove_plus: None,
540                    add_parentheses: None,
541                };
542
543                // a block on the LHS might have been intended to be an expression instead
544                if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
545                    err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
546                } else {
547                    err.remove_plus = Some(lo);
548                }
549                this.dcx().emit_err(err);
550
551                this.bump(); // `+`
552                Ok(this.parse_expr_prefix_common(lo)?.1)
553            }
554            // Recover from `++x`:
555            token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
556                let starts_stmt =
557                    this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
558                let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
559                // Eat both `+`s.
560                this.bump();
561                this.bump();
562
563                let operand_expr = this.parse_expr_dot_or_call(attrs)?;
564                this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
565            }
566            token::Ident(..) if this.token.is_keyword(kw::Box) => {
567                this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.parse_expr_box(lo)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.parse_expr_box(lo))
568            }
569            token::Ident(..)
570                if this.token.is_keyword(kw::Move)
571                    && this.look_ahead(1, |t| *t == token::OpenParen) =>
572            {
573                this.collect_tokens_for_expr(attrs,
    |this, attrs|
        {
            let (hi, ex) = this.parse_expr_move(lo)?;
            Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
        })make_it!(this, attrs, |this, _| this.parse_expr_move(lo))
574            }
575            token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
576                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))
577            }
578            _ => return this.parse_expr_dot_or_call(attrs),
579        }
580    }
581
582    fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {
583        let attrs = self.parse_outer_attributes()?;
584        let expr = if self.token.is_range_separator() {
585            self.parse_expr_prefix_range(attrs)
586        } else {
587            self.parse_expr_prefix(attrs)
588        }?;
589        let span = self.interpolated_or_expr_span(&expr);
590        Ok((lo.to(span), expr))
591    }
592
593    fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
594        self.bump(); // `op`
595        let (span, expr) = self.parse_expr_prefix_common(lo)?;
596        Ok((span, self.mk_unary(op, expr)))
597    }
598
599    /// Recover on `~expr` in favor of `!expr`.
600    fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
601        self.dcx().emit_err(diagnostics::TildeAsUnaryOperator(lo));
602
603        self.parse_expr_unary(lo, UnOp::Not)
604    }
605
606    /// Parse `box expr` - this syntax has been removed, but we still parse this
607    /// for now to provide a more useful error
608    fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> {
609        self.bump(); // `box`
610        let (span, expr) = self.parse_expr_prefix_common(box_kw)?;
611        // Make a multipart suggestion instead of `span_to_snippet` in case source isn't available
612        let box_kw_and_lo = box_kw.until(self.interpolated_or_expr_span(&expr));
613        let hi = span.shrink_to_hi();
614        let sugg = diagnostics::AddBoxNew { box_kw_and_lo, hi };
615        let guar = self.dcx().emit_err(diagnostics::BoxSyntaxRemoved { span, sugg });
616        Ok((span, ExprKind::Err(guar)))
617    }
618
619    fn parse_expr_move(&mut self, move_kw: Span) -> PResult<'a, (Span, ExprKind)> {
620        self.bump();
621        self.psess.gated_spans.gate(sym::move_expr, move_kw);
622        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
623        let expr = self.parse_expr()?;
624        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
625        let span = move_kw.to(self.prev_token.span);
626        Ok((span, ExprKind::Move(expr, move_kw)))
627    }
628
629    fn is_mistaken_not_ident_negation(&self) -> bool {
630        let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
631            // These tokens can start an expression after `!`, but
632            // can't continue an expression after an ident
633            token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),
634            token::Literal(..) | token::Pound => true,
635            _ => t.is_metavar_expr(),
636        };
637        self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
638    }
639
640    /// Recover on `not expr` in favor of `!expr`.
641    fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
642        let negated_token = self.look_ahead(1, |t| *t);
643
644        let sub_diag = if negated_token.is_numeric_lit() {
645            diagnostics::NotAsNegationOperatorSub::SuggestNotBitwise
646        } else if negated_token.is_bool_lit() {
647            diagnostics::NotAsNegationOperatorSub::SuggestNotLogical
648        } else {
649            diagnostics::NotAsNegationOperatorSub::SuggestNotDefault
650        };
651
652        self.dcx().emit_err(diagnostics::NotAsNegationOperator {
653            negated: negated_token.span,
654            negated_desc: super::token_descr(&negated_token),
655            // Span the `not` plus trailing whitespace to avoid
656            // trailing whitespace after the `!` in our suggestion
657            sub: sub_diag(
658                self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
659            ),
660        });
661
662        self.parse_expr_unary(lo, UnOp::Not)
663    }
664
665    /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
666    fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
667        match self.prev_token.kind {
668            token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
669            token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
670                // `expr.span` is the interpolated span, because invisible open
671                // and close delims both get marked with the same span, one
672                // that covers the entire thing between them. (See
673                // `rustc_expand::mbe::transcribe::transcribe`.)
674                self.prev_token.span
675            }
676            _ => expr.span,
677        }
678    }
679
680    fn parse_assoc_op_cast(
681        &mut self,
682        lhs: Box<Expr>,
683        lhs_span: Span,
684        op_span: Span,
685        expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind,
686    ) -> PResult<'a, Box<Expr>> {
687        let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| {
688            this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))
689        };
690
691        // Save the state of the parser before parsing type normally, in case there is a
692        // LessThan comparison after this cast.
693        let parser_snapshot_before_type = self.clone();
694        let cast_expr = match self.parse_as_cast_ty() {
695            Ok(rhs) => mk_expr(self, lhs, rhs),
696            Err(type_err) => {
697                if !self.may_recover() {
698                    return Err(type_err);
699                }
700
701                // Rewind to before attempting to parse the type with generics, to recover
702                // from situations like `x as usize < y` in which we first tried to parse
703                // `usize < y` as a type with generic arguments.
704                let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
705
706                // Check for typo of `'a: loop { break 'a }` with a missing `'`.
707                match (&lhs.kind, &self.token.kind) {
708                    (
709                        // `foo: `
710                        ExprKind::Path(None, ast::Path { segments, .. }),
711                        token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
712                    ) if let [segment] = segments.as_slice() => {
713                        let snapshot = self.create_snapshot_for_diagnostic();
714                        let label = Label {
715                            ident: Ident::from_str_and_span(
716                                &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\'{0}", segment.ident))
    })format!("'{}", segment.ident),
717                                segment.ident.span,
718                            ),
719                        };
720                        match self.parse_expr_labeled(label, false) {
721                            Ok(expr) => {
722                                type_err.cancel();
723                                self.dcx().emit_err(diagnostics::MalformedLoopLabel {
724                                    span: label.ident.span,
725                                    suggestion: label.ident.span.shrink_to_lo(),
726                                });
727                                return Ok(expr);
728                            }
729                            Err(err) => {
730                                err.cancel();
731                                self.restore_snapshot(snapshot);
732                            }
733                        }
734                    }
735                    _ => {}
736                }
737
738                match self.parse_path(PathStyle::Expr) {
739                    Ok(path) => {
740                        let span_after_type = parser_snapshot_after_type.token.span;
741                        let expr = mk_expr(
742                            self,
743                            lhs,
744                            self.mk_ty(path.span, TyKind::Path(None, path.clone())),
745                        );
746
747                        let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
748                        match self.token.kind {
749                            token::Lt => {
750                                self.dcx().emit_err(diagnostics::ComparisonInterpretedAsGeneric {
751                                    comparison: self.token.span,
752                                    r#type: pprust::path_to_string(&path),
753                                    args: args_span,
754                                    suggestion: diagnostics::ComparisonInterpretedAsGenericSugg {
755                                        left: expr.span.shrink_to_lo(),
756                                        right: expr.span.shrink_to_hi(),
757                                    },
758                                })
759                            }
760                            token::Shl => {
761                                self.dcx().emit_err(diagnostics::ShiftInterpretedAsGeneric {
762                                    shift: self.token.span,
763                                    r#type: pprust::path_to_string(&path),
764                                    args: args_span,
765                                    suggestion: diagnostics::ShiftInterpretedAsGenericSugg {
766                                        left: expr.span.shrink_to_lo(),
767                                        right: expr.span.shrink_to_hi(),
768                                    },
769                                })
770                            }
771                            _ => {
772                                // We can end up here even without `<` being the next token, for
773                                // example because `parse_ty_no_plus` returns `Err` on keywords,
774                                // but `parse_path` returns `Ok` on them due to error recovery.
775                                // Return original error and parser state.
776                                *self = parser_snapshot_after_type;
777                                return Err(type_err);
778                            }
779                        };
780
781                        // Successfully parsed the type path leaving a `<` yet to parse.
782                        type_err.cancel();
783
784                        // Keep `x as usize` as an expression in AST and continue parsing.
785                        expr
786                    }
787                    Err(path_err) => {
788                        // Couldn't parse as a path, return original error and parser state.
789                        path_err.cancel();
790                        *self = parser_snapshot_after_type;
791                        return Err(type_err);
792                    }
793                }
794            }
795        };
796
797        // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
798        // after a cast. If one is present, emit an error then return a valid
799        // parse tree; For something like `&x as T[0]` will be as if it was
800        // written `((&x) as T)[0]`.
801
802        let span = cast_expr.span;
803
804        let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
805
806        // Check if an illegal postfix operator has been added after the cast.
807        // If the resulting expression is not a cast, it is an illegal postfix operator.
808        if !#[allow(non_exhaustive_omitted_patterns)] match with_postfix.kind {
    ExprKind::Cast(_, _) => true,
    _ => false,
}matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
809            let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cast cannot be followed by {0}",
                match with_postfix.kind {
                    ExprKind::Index(..) => "indexing",
                    ExprKind::Try(_) => "`?`",
                    ExprKind::Field(_, _) => "a field access",
                    ExprKind::MethodCall(_) => "a method call",
                    ExprKind::Call(_, _) => "a function call",
                    ExprKind::Await(_, _) => "`.await`",
                    ExprKind::Use(_, _) => "`.use`",
                    ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
                    ExprKind::Match(_, _, MatchKind::Postfix) =>
                        "a postfix match",
                    ExprKind::Err(_) => return Ok(with_postfix),
                    _ => {
                        ::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)));
                    }
                }))
    })format!(
810                "cast cannot be followed by {}",
811                match with_postfix.kind {
812                    ExprKind::Index(..) => "indexing",
813                    ExprKind::Try(_) => "`?`",
814                    ExprKind::Field(_, _) => "a field access",
815                    ExprKind::MethodCall(_) => "a method call",
816                    ExprKind::Call(_, _) => "a function call",
817                    ExprKind::Await(_, _) => "`.await`",
818                    ExprKind::Use(_, _) => "`.use`",
819                    ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
820                    ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
821                    ExprKind::Err(_) => return Ok(with_postfix),
822                    _ => unreachable!(
823                        "did not expect {:?} as an illegal postfix operator following cast",
824                        with_postfix.kind
825                    ),
826                }
827            );
828            let mut err = self.dcx().struct_span_err(span, msg);
829
830            let suggest_parens = |err: &mut Diag<'_>| {
831                let suggestions = ::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![
832                    (span.shrink_to_lo(), "(".to_string()),
833                    (span.shrink_to_hi(), ")".to_string()),
834                ];
835                err.multipart_suggestion(
836                    "try surrounding the expression in parentheses",
837                    suggestions,
838                    Applicability::MachineApplicable,
839                );
840            };
841
842            suggest_parens(&mut err);
843
844            err.emit();
845        };
846        Ok(with_postfix)
847    }
848
849    /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
850    fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
851        self.expect_and()?;
852        let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
853        let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.
854        let (borrow_kind, mutbl) = self.parse_borrow_modifiers();
855        let (span, expr) = self.parse_expr_prefix_common(lo)?;
856        if let Some(lt) = lifetime {
857            self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
858        }
859
860        // Add expected tokens if we parsed `&raw` as an expression.
861        // This will make sure we see "expected `const`, `mut`", and
862        // guides recovery in case we write `&raw expr`.
863        if borrow_kind == ast::BorrowKind::Ref
864            && mutbl == ast::Mutability::Not
865            && #[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)
866        {
867            self.expected_token_types.insert(TokenType::KwMut);
868            self.expected_token_types.insert(TokenType::KwConst);
869        }
870
871        Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
872    }
873
874    fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
875        self.dcx()
876            .emit_err(diagnostics::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
877    }
878
879    /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
880    fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
881        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) {
882            // `raw [ const | mut ]`.
883            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));
884            if !found_raw { ::core::panicking::panic("assertion failed: found_raw") };assert!(found_raw);
885            let mutability = self.parse_mut_or_const().unwrap();
886            (ast::BorrowKind::Raw, mutability)
887        } else {
888            match self.parse_pin_and_mut() {
889                // `mut?`
890                (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),
891                // `pin [ const | mut ]`.
892                // `pin` has been gated in `self.parse_pin_and_mut()` so we don't
893                // need to gate it here.
894                (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),
895            }
896        }
897    }
898
899    /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
900    fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
901        self.collect_tokens_for_expr(attrs, |this, attrs| {
902            let base = this.parse_expr_bottom()?;
903            let span = this.interpolated_or_expr_span(&base);
904            this.parse_expr_dot_or_call_with(attrs, base, span)
905        })
906    }
907
908    pub(super) fn parse_expr_dot_or_call_with(
909        &mut self,
910        mut attrs: ast::AttrVec,
911        mut e: Box<Expr>,
912        lo: Span,
913    ) -> PResult<'a, Box<Expr>> {
914        let mut res = loop {
915            let has_question = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
916                // We are using noexpect here because we don't expect a `?` directly after
917                // a `return` which could be suggested otherwise.
918                self.eat_noexpect(&token::Question)
919            } else {
920                self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Question,
    token_type: crate::parser::token_type::TokenType::Question,
}exp!(Question))
921            };
922            if has_question {
923                // `expr?`
924                e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
925                continue;
926            }
927            let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
928                // We are using noexpect here because we don't expect a `.` directly after
929                // a `return` which could be suggested otherwise.
930                self.eat_noexpect(&token::Dot)
931            } else if self.token == TokenKind::RArrow && self.may_recover() {
932                // Recovery for `expr->suffix`.
933                self.bump();
934                let span = self.prev_token.span;
935                self.dcx().emit_err(diagnostics::ExprRArrowCall { span });
936                true
937            } else {
938                self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Dot,
    token_type: crate::parser::token_type::TokenType::Dot,
}exp!(Dot))
939            };
940            if has_dot {
941                // expr.f
942                e = self.parse_dot_suffix_expr(lo, e)?;
943                continue;
944            }
945            if self.expr_is_complete(&e) {
946                break Ok(e);
947            }
948            e = match self.token.kind {
949                token::OpenParen => self.parse_expr_fn_call(lo, e),
950                token::OpenBracket => self.parse_expr_index(lo, e)?,
951                _ => break Ok(e),
952            }
953        };
954
955        // Stitch the list of outer attributes onto the return value. A little
956        // bit ugly, but the best way given the current code structure.
957        if !attrs.is_empty()
958            && let Ok(expr) = &mut res
959        {
960            mem::swap(&mut expr.attrs, &mut attrs);
961            expr.attrs.extend(attrs)
962        }
963        res
964    }
965
966    pub(super) fn parse_dot_suffix_expr(
967        &mut self,
968        lo: Span,
969        base: Box<Expr>,
970    ) -> PResult<'a, Box<Expr>> {
971        // At this point we've consumed something like `expr.` and `self.token` holds the token
972        // after the dot.
973        match self.token.uninterpolate().kind {
974            token::Ident(..) => self.parse_dot_suffix(base, lo),
975            token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
976                let ident_span = self.token.span;
977                self.bump();
978                Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))
979            }
980            token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
981                Ok(match self.break_up_float(symbol, self.token.span) {
982                    // 1e2
983                    DestructuredFloat::Single(sym, _sp) => {
984                        // `foo.1e2`: a single complete dot access, fully consumed. We end up with
985                        // the `1e2` token in `self.prev_token` and the following token in
986                        // `self.token`.
987                        let ident_span = self.token.span;
988                        self.bump();
989                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
990                    }
991                    // 1.
992                    DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
993                        // `foo.1.`: a single complete dot access and the start of another.
994                        // We end up with the `sym` (`1`) token in `self.prev_token` and a dot in
995                        // `self.token`.
996                        if !suffix.is_none() {
    ::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
997                        self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);
998                        self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
999                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
1000                    }
1001                    // 1.2 | 1.2e3
1002                    DestructuredFloat::MiddleDot(
1003                        sym1,
1004                        ident1_span,
1005                        _dot_span,
1006                        sym2,
1007                        ident2_span,
1008                    ) => {
1009                        // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with
1010                        // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following
1011                        // token in `self.token`.
1012                        let next_token2 =
1013                            Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);
1014                        self.bump_with((next_token2, self.token_spacing));
1015                        self.bump();
1016                        let base1 =
1017                            self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
1018                        self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
1019                    }
1020                    DestructuredFloat::Error => base,
1021                })
1022            }
1023            _ => {
1024                self.error_unexpected_after_dot();
1025                Ok(base)
1026            }
1027        }
1028    }
1029
1030    fn error_unexpected_after_dot(&self) {
1031        let actual = super::token_descr(&self.token);
1032        let span = self.token.span;
1033        let sm = self.psess.source_map();
1034        let (span, actual) = match (&self.token.kind, self.subparser_name) {
1035            (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
1036                (span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", snippet))
    })format!("`{}`", snippet))
1037            }
1038            (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
1039                // No need to report an error. This case will only occur when parsing a pasted
1040                // metavariable, and we should have emitted an error when parsing the macro call in
1041                // the first place. E.g. in this code:
1042                // ```
1043                // macro_rules! m { ($e:expr) => { $e }; }
1044                //
1045                // fn main() {
1046                //     let f = 1;
1047                //     m!(f.);
1048                // }
1049                // ```
1050                // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't
1051                // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`
1052                // represent the invisible delimiters).
1053                self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");
1054                return;
1055            }
1056            _ => (span, actual),
1057        };
1058        self.dcx().emit_err(diagnostics::UnexpectedTokenAfterDot { span, actual });
1059    }
1060
1061    /// We need an identifier or integer, but the next token is a float.
1062    /// Break the float into components to extract the identifier or integer.
1063    ///
1064    /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.
1065    //
1066    // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
1067    //  parts unless those parts are processed immediately. `TokenCursor` should either
1068    //  support pushing "future tokens" (would be also helpful to `break_and_eat`), or
1069    //  we should break everything including floats into more basic proc-macro style
1070    //  tokens in the lexer (probably preferable).
1071    pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
1072        #[derive(#[automatically_derived]
impl ::core::fmt::Debug for FloatComponent {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            FloatComponent::IdentLike(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "IdentLike", &__self_0),
            FloatComponent::Punct(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Punct",
                    &__self_0),
        }
    }
}Debug)]
1073        enum FloatComponent {
1074            IdentLike(String),
1075            Punct(char),
1076        }
1077        use FloatComponent::*;
1078
1079        let float_str = float.as_str();
1080        let mut components = Vec::new();
1081        let mut ident_like = String::new();
1082        for c in float_str.chars() {
1083            if c == '_' || c.is_ascii_alphanumeric() {
1084                ident_like.push(c);
1085            } else if #[allow(non_exhaustive_omitted_patterns)] match c {
    '.' | '+' | '-' => true,
    _ => false,
}matches!(c, '.' | '+' | '-') {
1086                if !ident_like.is_empty() {
1087                    components.push(IdentLike(mem::take(&mut ident_like)));
1088                }
1089                components.push(Punct(c));
1090            } else {
1091                {
    ::core::panicking::panic_fmt(format_args!("unexpected character in a float token: {0:?}",
            c));
}panic!("unexpected character in a float token: {c:?}")
1092            }
1093        }
1094        if !ident_like.is_empty() {
1095            components.push(IdentLike(ident_like));
1096        }
1097
1098        // With proc macros the span can refer to anything, the source may be too short,
1099        // or too long, or non-ASCII. It only makes sense to break our span into components
1100        // if its underlying text is identical to our float literal.
1101        let can_take_span_apart =
1102            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
1103
1104        match &*components {
1105            // 1e2
1106            [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span),
1107            // 1.
1108            [IdentLike(left), Punct('.')] => {
1109                let (left_span, dot_span) = if can_take_span_apart() {
1110                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1111                    let dot_span = span.with_lo(left_span.hi());
1112                    (left_span, dot_span)
1113                } else {
1114                    (span, span)
1115                };
1116                let left = Symbol::intern(left);
1117                DestructuredFloat::TrailingDot(left, left_span, dot_span)
1118            }
1119            // 1.2 | 1.2e3
1120            [IdentLike(left), Punct('.'), IdentLike(right)] => {
1121                let (left_span, dot_span, right_span) = if can_take_span_apart() {
1122                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1123                    let dot_span =
1124                        span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
1125                    let right_span = span.with_lo(dot_span.hi());
1126                    (left_span, dot_span, right_span)
1127                } else {
1128                    (span, span, span)
1129                };
1130                let left = Symbol::intern(left);
1131                let right = Symbol::intern(right);
1132                DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
1133            }
1134            // 1e+ | 1e- (recovered)
1135            [IdentLike(_), Punct('+' | '-')] |
1136            // 1e+2 | 1e-2
1137            [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
1138            // 1.2e+ | 1.2e-
1139            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
1140            // 1.2e+3 | 1.2e-3
1141            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
1142                // See the FIXME about `TokenCursor` above.
1143                self.error_unexpected_after_dot();
1144                DestructuredFloat::Error
1145            }
1146            _ => {
    ::core::panicking::panic_fmt(format_args!("unexpected components in a float token: {0:?}",
            components));
}panic!("unexpected components in a float token: {components:?}"),
1147        }
1148    }
1149
1150    /// Parse the field access used in offset_of, matched by `$(e:expr)+`.
1151    /// Currently returns a list of idents. However, it should be possible in
1152    /// future to also do array indices, which might be arbitrary expressions.
1153    pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, ThinVec<Ident>> {
1154        let mut fields = ThinVec::new();
1155        let mut trailing_dot = None;
1156
1157        loop {
1158            // This is expected to use a metavariable $(args:expr)+, but the builtin syntax
1159            // could be called directly. Calling `parse_expr` allows this function to only
1160            // consider `Expr`s.
1161            let expr = self.parse_expr()?;
1162            let mut current = &expr;
1163            let start_idx = fields.len();
1164            loop {
1165                match current.kind {
1166                    ExprKind::Field(ref left, right) => {
1167                        // Field access is read right-to-left.
1168                        fields.insert(start_idx, right);
1169                        trailing_dot = None;
1170                        current = left;
1171                    }
1172                    // Parse this both to give helpful error messages and to
1173                    // verify it can be done with this parser setup.
1174                    ExprKind::Index(ref left, ref _right, span) => {
1175                        self.dcx().emit_err(diagnostics::ArrayIndexInOffsetOf(span));
1176                        current = left;
1177                    }
1178                    ExprKind::Lit(token::Lit {
1179                        kind: token::Float | token::Integer,
1180                        symbol,
1181                        suffix,
1182                    }) => {
1183                        if let Some(suffix) = suffix {
1184                            self.dcx().emit_err(diagnostics::InvalidLiteralSuffixOnTupleIndex {
1185                                span: current.span,
1186                                suffix,
1187                            });
1188                        }
1189                        match self.break_up_float(symbol, current.span) {
1190                            // 1e2
1191                            DestructuredFloat::Single(sym, sp) => {
1192                                trailing_dot = None;
1193                                fields.insert(start_idx, Ident::new(sym, sp));
1194                            }
1195                            // 1.
1196                            DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1197                                if !suffix.is_none() {
    ::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
1198                                trailing_dot = Some(dot_span);
1199                                fields.insert(start_idx, Ident::new(sym, sym_span));
1200                            }
1201                            // 1.2 | 1.2e3
1202                            DestructuredFloat::MiddleDot(
1203                                symbol1,
1204                                span1,
1205                                _dot_span,
1206                                symbol2,
1207                                span2,
1208                            ) => {
1209                                trailing_dot = None;
1210                                fields.insert(start_idx, Ident::new(symbol2, span2));
1211                                fields.insert(start_idx, Ident::new(symbol1, span1));
1212                            }
1213                            DestructuredFloat::Error => {
1214                                trailing_dot = None;
1215                                fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
1216                            }
1217                        }
1218                        break;
1219                    }
1220                    ExprKind::Path(None, Path { ref segments, .. }) => {
1221                        match &segments[..] {
1222                            [PathSegment { ident, args: None, .. }] => {
1223                                trailing_dot = None;
1224                                fields.insert(start_idx, *ident)
1225                            }
1226                            _ => {
1227                                self.dcx().emit_err(diagnostics::InvalidOffsetOf(current.span));
1228                                break;
1229                            }
1230                        }
1231                        break;
1232                    }
1233                    _ => {
1234                        self.dcx().emit_err(diagnostics::InvalidOffsetOf(current.span));
1235                        break;
1236                    }
1237                }
1238            }
1239
1240            if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
1241                break;
1242            } else if trailing_dot.is_none() {
1243                // This loop should only repeat if there is a trailing dot.
1244                self.dcx().emit_err(diagnostics::InvalidOffsetOf(self.token.span));
1245                break;
1246            }
1247        }
1248        if let Some(dot) = trailing_dot {
1249            self.dcx().emit_err(diagnostics::InvalidOffsetOf(dot));
1250        }
1251        Ok(fields.into_iter().collect())
1252    }
1253
1254    fn mk_expr_tuple_field_access(
1255        &self,
1256        lo: Span,
1257        ident_span: Span,
1258        base: Box<Expr>,
1259        field: Symbol,
1260        suffix: Option<Symbol>,
1261    ) -> Box<Expr> {
1262        if let Some(suffix) = suffix {
1263            self.dcx().emit_err(diagnostics::InvalidLiteralSuffixOnTupleIndex {
1264                span: ident_span,
1265                suffix,
1266            });
1267        }
1268        self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
1269    }
1270
1271    /// Parse a function call expression, `expr(...)`.
1272    fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {
1273        let snapshot = if self.token == token::OpenParen {
1274            Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
1275        } else {
1276            None
1277        };
1278        let open_paren = self.token.span;
1279        let call_depth = self.token_cursor.depth();
1280
1281        let seq = match self.parse_expr_paren_seq() {
1282            Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),
1283            Err(err)
1284                if self.is_expected_raw_ref_mut() && self.token_cursor.depth() == call_depth =>
1285            {
1286                let guar = err.emit();
1287                // Preserve the call expression so later passes can still diagnose the callee,
1288                // while treating the malformed `&raw <expr>` argument as an error expression.
1289                let args = self.recover_raw_ref_call_args(guar);
1290                return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));
1291            }
1292            Err(err) => Err(err),
1293        };
1294        match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
1295            Ok(expr) => expr,
1296            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),
1297        }
1298    }
1299
1300    fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {
1301        let err_span = self.prev_token.span.to(self.token.span);
1302        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)];
1303        while !self.token.kind.is_close_delim_or_eof() {
1304            if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1305                if !self.token.kind.is_close_delim_or_eof() {
1306                    args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));
1307                }
1308            } else {
1309                self.parse_token_tree();
1310            }
1311        }
1312        let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen));
1313        args
1314    }
1315
1316    /// If we encounter a parser state that looks like the user has written a `struct` literal with
1317    /// parentheses instead of braces, recover the parser state and provide suggestions.
1318    #[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("compiler/rustc_parse/src/parser/expr.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1318u32),
                                    ::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().create_err(diagnostics::ParenthesesWithStructFields {
                                                span,
                                                braces_for_struct: diagnostics::BracesForStructLiteral {
                                                    first: open_paren,
                                                    second: close_paren,
                                                    r#type: type_str.clone(),
                                                },
                                                no_fields_for_fn: diagnostics::NoFieldsForFnCall {
                                                    r#type: type_str,
                                                    fields: fields.into_iter().map(|field|
                                                                field.span.until(field.expr.span)).collect(),
                                                },
                                            }).emit()
                                } else { err.emit() };
                            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")]
1319    fn maybe_recover_struct_lit_bad_delims(
1320        &mut self,
1321        lo: Span,
1322        open_paren: Span,
1323        seq: PResult<'a, Box<Expr>>,
1324        snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
1325    ) -> PResult<'a, Box<Expr>> {
1326        match (self.may_recover(), seq, snapshot) {
1327            (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
1328                snapshot.bump(); // `(`
1329                match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
1330                    Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
1331                        // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
1332                        // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
1333                        self.restore_snapshot(snapshot);
1334                        let close_paren = self.prev_token.span;
1335                        let span = lo.to(close_paren);
1336                        // filter shorthand fields
1337                        let fields: Vec<_> =
1338                            fields.into_iter().filter(|field| !field.is_shorthand).collect();
1339
1340                        let guar = if !fields.is_empty() &&
1341                            // `token.kind` should not be compared here.
1342                            // This is because the `snapshot.token.kind` is treated as the same as
1343                            // that of the open delim in `TokenTreesReader::parse_token_tree`, even
1344                            // if they are different.
1345                            self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
1346                        {
1347                            err.cancel();
1348                            let type_str = pprust::path_to_string(&path);
1349                            self.dcx()
1350                                .create_err(diagnostics::ParenthesesWithStructFields {
1351                                    span,
1352                                    braces_for_struct: diagnostics::BracesForStructLiteral {
1353                                        first: open_paren,
1354                                        second: close_paren,
1355                                        r#type: type_str.clone(),
1356                                    },
1357                                    no_fields_for_fn: diagnostics::NoFieldsForFnCall {
1358                                        r#type: type_str,
1359                                        fields: fields
1360                                            .into_iter()
1361                                            .map(|field| field.span.until(field.expr.span))
1362                                            .collect(),
1363                                    },
1364                                })
1365                                .emit()
1366                        } else {
1367                            err.emit()
1368                        };
1369                        Ok(self.mk_expr_err(span, guar))
1370                    }
1371                    Ok(_) => Err(err),
1372                    Err(err2) => {
1373                        err2.cancel();
1374                        Err(err)
1375                    }
1376                }
1377            }
1378            (_, seq, _) => seq,
1379        }
1380    }
1381
1382    /// Parse an indexing expression `expr[...]`.
1383    fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {
1384        let prev_token = self.prev_token;
1385        let open_delim_span = self.token.span;
1386        self.bump(); // `[`
1387        let index = self.parse_expr()?;
1388        self.suggest_missing_semicolon_before_array(prev_token.span, open_delim_span)?;
1389        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 e| {
1390            if let TokenKind::Ident(_, _) = prev_token.kind {
1391                e.span_suggestion_verbose(
1392                    prev_token.span.shrink_to_hi(),
1393                    "you might have meant to call a macro",
1394                    "!".to_string(),
1395                    Applicability::MaybeIncorrect,
1396                );
1397            }
1398            e
1399        })?;
1400        Ok(self.mk_expr(
1401            lo.to(self.prev_token.span),
1402            self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
1403        ))
1404    }
1405
1406    /// Assuming we have just parsed `.`, continue parsing into an expression.
1407    fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {
1408        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)) {
1409            return Ok(self.mk_await_expr(self_arg, lo));
1410        }
1411
1412        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)) {
1413            let use_span = self.prev_token.span;
1414            self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
1415            return Ok(self.mk_use_expr(self_arg, lo));
1416        }
1417
1418        // Post-fix match
1419        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)) {
1420            let match_span = self.prev_token.span;
1421            self.psess.gated_spans.gate(sym::postfix_match, match_span);
1422            return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1423        }
1424
1425        // Parse a postfix `yield`.
1426        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)) {
1427            let yield_span = self.prev_token.span;
1428            self.psess.gated_spans.gate(sym::yield_expr, yield_span);
1429            return Ok(
1430                self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
1431            );
1432        }
1433
1434        let fn_span_lo = self.token.span;
1435        let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
1436        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)]);
1437        self.check_turbofish_missing_angle_brackets(&mut seg);
1438
1439        if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1440            // Method call `expr.f()`
1441            let args = self.parse_expr_paren_seq()?;
1442            let fn_span = fn_span_lo.to(self.prev_token.span);
1443            let span = lo.to(self.prev_token.span);
1444            Ok(self.mk_expr(
1445                span,
1446                ExprKind::MethodCall(Box::new(ast::MethodCall {
1447                    seg,
1448                    receiver: self_arg,
1449                    args,
1450                    span: fn_span,
1451                })),
1452            ))
1453        } else {
1454            // Field access `expr.f`
1455            let span = lo.to(self.prev_token.span);
1456            if let Some(args) = seg.args {
1457                // See `StashKey::GenericInFieldExpr` for more info on why we stash this.
1458                self.dcx()
1459                    .create_err(diagnostics::FieldExpressionWithGeneric(args.span()))
1460                    .stash(seg.ident.span, StashKey::GenericInFieldExpr);
1461            }
1462
1463            Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
1464        }
1465    }
1466
1467    /// At the bottom (top?) of the precedence hierarchy,
1468    /// Parses things like parenthesized exprs, macros, `return`, etc.
1469    ///
1470    /// N.B., this does not parse outer attributes, and is private because it only works
1471    /// correctly if called from `parse_expr_dot_or_call`.
1472    fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {
1473        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);
1474
1475        let span = self.token.span;
1476        if let Some(expr) = self.eat_metavar_seq_with_matcher(
1477            |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
    MetaVarKind::Expr { .. } => true,
    _ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
1478            |this| {
1479                // Force collection (as opposed to just `parse_expr`) is required to avoid the
1480                // attribute duplication seen in #138478.
1481                let expr = this.parse_expr_force_collect();
1482                // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly
1483                // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line
1484                // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in
1485                // `compiler/rustc_index/src/bit_set/tests.rs`.
1486                if this.token.kind == token::Comma {
1487                    this.bump();
1488                }
1489                expr
1490            },
1491        ) {
1492            return Ok(expr);
1493        } else if let Some(lit) =
1494            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
1495        {
1496            return Ok(lit);
1497        } else if let Some(block) =
1498            self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
1499        {
1500            return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
1501        } else if let Some(path) =
1502            self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
1503        {
1504            return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
1505        }
1506
1507        // Outer attributes are already parsed and will be
1508        // added to the return value after the fact.
1509
1510        let restrictions = self.restrictions;
1511        self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
1512            // Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.
1513            let lo = this.token.span;
1514            if let token::Literal(_) = this.token.kind {
1515                // This match arm is a special-case of the `_` match arm below and
1516                // could be removed without changing functionality, but it's faster
1517                // to have it here, especially for programs with large constants.
1518                this.parse_expr_lit()
1519            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1520                this.parse_expr_tuple_parens(restrictions)
1521            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
1522                if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1523                    return Ok(expr);
1524                }
1525                this.parse_expr_block(None, lo, BlockCheckMode::Default)
1526            } 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)) {
1527                this.parse_expr_closure().map_err(|mut err| {
1528                    // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
1529                    // then suggest parens around the lhs.
1530                    if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
1531                        err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
1532                    }
1533                    err
1534                })
1535            } else if this.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBracket,
    token_type: crate::parser::token_type::TokenType::OpenBracket,
}exp!(OpenBracket)) {
1536                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))
1537            } else if this.is_builtin() {
1538                this.parse_expr_builtin()
1539            } else if this.check_path() {
1540                this.parse_expr_path_start()
1541            } 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))
1542                || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Use,
    token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use))
1543                || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Static,
    token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static))
1544                || this.check_const_closure()
1545            {
1546                this.parse_expr_closure()
1547            } 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)) {
1548                this.parse_expr_if()
1549            } 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)) {
1550                if this.choose_generics_over_qpath(1) {
1551                    this.parse_expr_closure()
1552                } else {
1553                    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)));
1554                    this.parse_expr_for(None, lo)
1555                }
1556            } 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)) {
1557                this.parse_expr_while(None, lo)
1558            } else if let Some(label) = this.eat_label() {
1559                this.parse_expr_labeled(label, true)
1560            } 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)) {
1561                this.parse_expr_loop(None, lo).map_err(|mut err| {
1562                    err.span_label(lo, "while parsing this `loop` expression");
1563                    err
1564                })
1565            } 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)) {
1566                this.parse_expr_match().map_err(|mut err| {
1567                    err.span_label(lo, "while parsing this `match` expression");
1568                    err
1569                })
1570            } 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)) {
1571                this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
1572                    |mut err| {
1573                        err.span_label(lo, "while parsing this `unsafe` expression");
1574                        err
1575                    },
1576                )
1577            } else if this.check_inline_const(0) {
1578                this.parse_const_block(lo, false)
1579            } else if this.may_recover() && this.is_do_catch_block() {
1580                this.recover_do_catch()
1581            } else if this.is_try_block() {
1582                this.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Try,
    token_type: crate::parser::token_type::TokenType::KwTry,
}exp!(Try))?;
1583                this.parse_try_block(lo)
1584            } 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)) {
1585                this.parse_expr_return()
1586            } 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)) {
1587                this.parse_expr_continue(lo)
1588            } 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)) {
1589                this.parse_expr_break()
1590            } 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)) {
1591                this.parse_expr_yield()
1592            } else if this.is_do_yeet() {
1593                this.parse_expr_yeet()
1594            } 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)) {
1595                this.parse_expr_become()
1596            } 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)) {
1597                this.parse_expr_let(restrictions)
1598            } 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)) {
1599                if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1600                    return Ok(expr);
1601                }
1602                Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
1603            } else if this.token_uninterpolated_span().at_least_rust_2018() {
1604                // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
1605                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));
1606                // check for `gen {}` and `gen move {}`
1607                // or `async gen {}` and `async gen move {}`
1608                // FIXME: (async) gen closures aren't yet parsed.
1609                // FIXME(gen_blocks): Parse `gen async` and suggest swap
1610                if this.token_uninterpolated_span().at_least_rust_2024()
1611                    && this.is_gen_block(kw::Gen, at_async as usize)
1612                {
1613                    this.parse_gen_block()
1614                // Check for `async {` and `async move {`,
1615                } else if this.is_gen_block(kw::Async, 0) {
1616                    this.parse_gen_block()
1617                } else if at_async {
1618                    this.parse_expr_closure()
1619                } else if this.eat_keyword_noexpect(kw::Await) {
1620                    this.recover_incorrect_await_syntax(lo)
1621                } else {
1622                    this.parse_expr_lit()
1623                }
1624            } else {
1625                this.parse_expr_lit()
1626            }
1627        })
1628    }
1629
1630    fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {
1631        let lo = self.token.span;
1632        match self.parse_opt_token_lit() {
1633            Some((token_lit, _)) => {
1634                let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));
1635                self.maybe_recover_from_bad_qpath(expr)
1636            }
1637            None => self.try_macro_suggestion(),
1638        }
1639    }
1640
1641    fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
1642        let lo = self.token.span;
1643        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1644        let (es, trailing_comma) = match self.parse_seq_to_end(
1645            crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1646            SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
1647            |p| p.parse_expr_catch_underscore(restrictions.intersection(Restrictions::ALLOW_LET)),
1648        ) {
1649            Ok(x) => x,
1650            Err(err) => {
1651                return Ok(self.recover_seq_parse_error(
1652                    crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen),
1653                    crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1654                    lo,
1655                    err,
1656                ));
1657            }
1658        };
1659        let kind = if es.len() == 1 && #[allow(non_exhaustive_omitted_patterns)] match trailing_comma {
    Trailing::No => true,
    _ => false,
}matches!(trailing_comma, Trailing::No) {
1660            // `(e)` is parenthesized `e`.
1661            ExprKind::Paren(es.into_iter().next().unwrap())
1662        } else {
1663            // `(e,)` is a tuple with only one field, `e`.
1664            ExprKind::Tup(es)
1665        };
1666        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1667        self.maybe_recover_from_bad_qpath(expr)
1668    }
1669
1670    fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {
1671        let lo = self.token.span;
1672        self.bump(); // `[` or other open delim
1673
1674        let kind = if self.eat(close) {
1675            // Empty vector
1676            ExprKind::Array(ThinVec::new())
1677        } else {
1678            // Non-empty vector
1679            let first_expr = self.parse_expr()?;
1680            if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Semi,
    token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
1681                // Repeating array syntax: `[ 0; 512 ]`
1682                let count = self.parse_expr_anon_const()?;
1683                self.expect(close)?;
1684                ExprKind::Repeat(first_expr, count)
1685            } else if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1686                // Vector with two or more elements.
1687                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));
1688                let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
1689                exprs.insert(0, first_expr);
1690                ExprKind::Array(exprs)
1691            } else {
1692                // Vector with one element
1693                self.expect(close)?;
1694                ExprKind::Array({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(first_expr);
    vec
}thin_vec![first_expr])
1695            }
1696        };
1697        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1698        self.maybe_recover_from_bad_qpath(expr)
1699    }
1700
1701    fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {
1702        let maybe_eq_tok = self.prev_token;
1703        let (qself, path) = if self.eat_lt() {
1704            let lt_span = self.prev_token.span;
1705            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
1706                // Suggests using '<=' if there is an error parsing qpath when the previous token
1707                // is an '=' token. Only emits suggestion if the '<' token and '=' token are
1708                // directly adjacent (i.e. '=<')
1709                if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
1710                    let eq_lt = maybe_eq_tok.span.to(lt_span);
1711                    err.span_suggestion_verbose(
1712                        eq_lt,
1713                        "you might have meant to write a \"less than or equal to\" comparison",
1714                        "<=",
1715                        Applicability::Unspecified,
1716                    );
1717                }
1718                err
1719            })?;
1720            (Some(qself), path)
1721        } else {
1722            (None, self.parse_path(PathStyle::Expr)?)
1723        };
1724
1725        // `!`, as an operator, is prefix, so we know this isn't that.
1726        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)) {
1727            // MACRO INVOCATION expression
1728            if qself.is_some() {
1729                self.dcx().emit_err(diagnostics::MacroInvocationWithQualifiedPath(path.span));
1730            }
1731            let lo = path.span;
1732            let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });
1733            (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
1734        } else if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
1735            && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
1736        {
1737            if qself.is_some() {
1738                self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);
1739            }
1740            return expr;
1741        } else {
1742            (path.span, ExprKind::Path(qself, path))
1743        };
1744
1745        let expr = self.mk_expr(span, kind);
1746        self.maybe_recover_from_bad_qpath(expr)
1747    }
1748
1749    /// Parse `'label: $expr`. The label is already parsed.
1750    pub(super) fn parse_expr_labeled(
1751        &mut self,
1752        label_: Label,
1753        mut consume_colon: bool,
1754    ) -> PResult<'a, Box<Expr>> {
1755        let lo = label_.ident.span;
1756        let label = Some(label_);
1757        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));
1758        let tok_sp = self.token.span;
1759        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)) {
1760            self.parse_expr_while(label, lo)
1761        } 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)) {
1762            self.parse_expr_for(label, lo)
1763        } 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)) {
1764            self.parse_expr_loop(label, lo)
1765        } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
1766            self.parse_expr_block(label, lo, BlockCheckMode::Default)
1767        } else if !ate_colon
1768            && self.may_recover()
1769            && (self.token.kind.close_delim().is_some() || self.token.is_punct())
1770            && could_be_unclosed_char_literal(label_.ident)
1771        {
1772            let (lit, _) =
1773                self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
1774                    self_.dcx().create_err(diagnostics::UnexpectedTokenAfterLabel {
1775                        span: self_.token.span,
1776                        remove_label: None,
1777                        enclose_in_block: None,
1778                    })
1779                });
1780            consume_colon = false;
1781            Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
1782        } else if !ate_colon
1783            && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
1784        {
1785            // We're probably inside of a `Path<'a>` that needs a turbofish
1786            let guar = self.dcx().emit_err(diagnostics::UnexpectedTokenAfterLabel {
1787                span: self.token.span,
1788                remove_label: None,
1789                enclose_in_block: None,
1790            });
1791            consume_colon = false;
1792            Ok(self.mk_expr_err(lo, guar))
1793        } else {
1794            let mut err = diagnostics::UnexpectedTokenAfterLabel {
1795                span: self.token.span,
1796                remove_label: None,
1797                enclose_in_block: None,
1798            };
1799
1800            // Continue as an expression in an effort to recover on `'label: non_block_expr`.
1801            let expr = self.parse_expr().map(|expr| {
1802                let span = expr.span;
1803
1804                let found_labeled_breaks = {
1805                    struct FindLabeledBreaksVisitor;
1806
1807                    impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
1808                        type Result = ControlFlow<()>;
1809                        fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
1810                            if let ExprKind::Break(Some(_label), _) = ex.kind {
1811                                ControlFlow::Break(())
1812                            } else {
1813                                walk_expr(self, ex)
1814                            }
1815                        }
1816                    }
1817
1818                    FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
1819                };
1820
1821                // Suggestion involves adding a labeled block.
1822                //
1823                // If there are no breaks that may use this label, suggest removing the label and
1824                // recover to the unmodified expression.
1825                if !found_labeled_breaks {
1826                    err.remove_label = Some(lo.until(span));
1827
1828                    return expr;
1829                }
1830
1831                err.enclose_in_block = Some(diagnostics::UnexpectedTokenAfterLabelSugg {
1832                    left: span.shrink_to_lo(),
1833                    right: span.shrink_to_hi(),
1834                });
1835
1836                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
1837                let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
1838                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);
1839                self.mk_expr(span, ExprKind::Block(blk, label))
1840            });
1841
1842            self.dcx().emit_err(err);
1843            expr
1844        }?;
1845
1846        if !ate_colon && consume_colon {
1847            self.dcx().emit_err(diagnostics::RequireColonAfterLabeledExpression {
1848                span: expr.span,
1849                label: lo,
1850                label_end: lo.between(tok_sp),
1851            });
1852        }
1853
1854        Ok(expr)
1855    }
1856
1857    /// Emit an error when a char is parsed as a lifetime or label because of a missing quote.
1858    pub(super) fn recover_unclosed_char<L>(
1859        &self,
1860        ident: Ident,
1861        mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1862        err: impl FnOnce(&Self) -> Diag<'a>,
1863    ) -> L {
1864        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));
1865        self.dcx()
1866            .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {
1867                err.span_suggestion_verbose(
1868                    ident.span.shrink_to_hi(),
1869                    "add `'` to close the char literal",
1870                    "'",
1871                    Applicability::MaybeIncorrect,
1872                );
1873            })
1874            .unwrap_or_else(|| {
1875                err(self)
1876                    .with_span_suggestion_verbose(
1877                        ident.span.shrink_to_hi(),
1878                        "add `'` to close the char literal",
1879                        "'",
1880                        Applicability::MaybeIncorrect,
1881                    )
1882                    .emit()
1883            });
1884        let name = ident.without_first_quote().name;
1885        mk_lit_char(name, ident.span)
1886    }
1887
1888    /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
1889    fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {
1890        let lo = self.token.span;
1891
1892        self.bump(); // `do`
1893        self.bump(); // `catch`
1894
1895        let span = lo.to(self.prev_token.span);
1896        self.dcx().emit_err(diagnostics::DoCatchSyntaxRemoved { span });
1897
1898        self.parse_try_block(lo)
1899    }
1900
1901    /// Parse an expression if the token can begin one.
1902    fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {
1903        Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })
1904    }
1905
1906    /// Parse `"return" expr?`.
1907    fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {
1908        let lo = self.prev_token.span;
1909        let kind = ExprKind::Ret(self.parse_expr_opt()?);
1910        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1911        self.maybe_recover_from_bad_qpath(expr)
1912    }
1913
1914    /// Parse `"do" "yeet" expr?`.
1915    fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {
1916        let lo = self.token.span;
1917
1918        self.bump(); // `do`
1919        self.bump(); // `yeet`
1920
1921        let kind = ExprKind::Yeet(self.parse_expr_opt()?);
1922
1923        let span = lo.to(self.prev_token.span);
1924        self.psess.gated_spans.gate(sym::yeet_expr, span);
1925        let expr = self.mk_expr(span, kind);
1926        self.maybe_recover_from_bad_qpath(expr)
1927    }
1928
1929    /// Parse `"become" expr`, with `"become"` token already eaten.
1930    fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {
1931        let lo = self.prev_token.span;
1932        let kind = ExprKind::Become(self.parse_expr()?);
1933        let span = lo.to(self.prev_token.span);
1934        self.psess.gated_spans.gate(sym::explicit_tail_calls, span);
1935        let expr = self.mk_expr(span, kind);
1936        self.maybe_recover_from_bad_qpath(expr)
1937    }
1938
1939    /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
1940    /// If the label is followed immediately by a `:` token, the label and `:` are
1941    /// parsed as part of the expression (i.e. a labeled loop). The language team has
1942    /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
1943    /// the break expression of an unlabeled break is a labeled loop (as in
1944    /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
1945    /// expression only gets a warning for compatibility reasons; and a labeled break
1946    /// with a labeled loop does not even get a warning because there is no ambiguity.
1947    fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
1948        let lo = self.prev_token.span;
1949        let mut label = self.eat_label();
1950        let kind = if self.token == token::Colon
1951            && let Some(label) = label.take()
1952        {
1953            // The value expression can be a labeled loop, see issue #86948, e.g.:
1954            // `loop { break 'label: loop { break 'label 42; }; }`
1955            let lexpr = self.parse_expr_labeled(label, true)?;
1956            self.dcx().emit_err(diagnostics::LabeledLoopInBreak {
1957                span: lexpr.span,
1958                sub: diagnostics::WrapInParentheses::Expression {
1959                    left: lexpr.span.shrink_to_lo(),
1960                    right: lexpr.span.shrink_to_hi(),
1961                },
1962            });
1963            Some(lexpr)
1964        } else if self.token != token::OpenBrace
1965            || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
1966        {
1967            let mut expr = self.parse_expr_opt()?;
1968            if let Some(expr) = &mut expr {
1969                if label.is_some()
1970                    && match &expr.kind {
1971                        ExprKind::While(_, _, None)
1972                        | ExprKind::ForLoop(ForLoop { label: None, .. })
1973                        | ExprKind::Loop(_, None, _) => true,
1974                        ExprKind::Block(block, None) => {
1975                            #[allow(non_exhaustive_omitted_patterns)] match block.rules {
    BlockCheckMode::Default => true,
    _ => false,
}matches!(block.rules, BlockCheckMode::Default)
1976                        }
1977                        _ => false,
1978                    }
1979                {
1980                    let span = expr.span;
1981                    self.psess.buffer_lint(
1982                        BREAK_WITH_LABEL_AND_LOOP,
1983                        lo.to(expr.span),
1984                        ast::CRATE_NODE_ID,
1985                        diagnostics::BreakWithLabelAndLoop {
1986                            sub: diagnostics::BreakWithLabelAndLoopSub {
1987                                left: span.shrink_to_lo(),
1988                                right: span.shrink_to_hi(),
1989                            },
1990                        },
1991                    );
1992                }
1993
1994                // Recover `break label aaaaa`
1995                if self.may_recover()
1996                    && let ExprKind::Path(None, p) = &expr.kind
1997                    && let [segment] = &*p.segments
1998                    && let &ast::PathSegment { ident, args: None, .. } = segment
1999                    && let Some(next) = self.parse_expr_opt()?
2000                {
2001                    label = Some(self.recover_ident_into_label(ident));
2002                    *expr = next;
2003                }
2004            }
2005
2006            expr
2007        } else {
2008            None
2009        };
2010        let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
2011        self.maybe_recover_from_bad_qpath(expr)
2012    }
2013
2014    /// Parse `"continue" label?`.
2015    fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2016        let mut label = self.eat_label();
2017
2018        // Recover `continue label` -> `continue 'label`
2019        if self.may_recover()
2020            && label.is_none()
2021            && let Some((ident, _)) = self.token.ident()
2022        {
2023            self.bump();
2024            label = Some(self.recover_ident_into_label(ident));
2025        }
2026
2027        let kind = ExprKind::Continue(label);
2028        Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
2029    }
2030
2031    /// Parse `"yield" expr?`.
2032    fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {
2033        let lo = self.prev_token.span;
2034        let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
2035        let span = lo.to(self.prev_token.span);
2036        self.psess.gated_spans.gate(sym::yield_expr, span);
2037        let expr = self.mk_expr(span, kind);
2038        self.maybe_recover_from_bad_qpath(expr)
2039    }
2040
2041    /// Parse `builtin # ident(args,*)`.
2042    fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> {
2043        self.parse_builtin(|this, lo, ident| {
2044            Ok(match ident.name {
2045                sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
2046                sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
2047                sym::wrap_binder => {
2048                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
2049                }
2050                sym::unwrap_binder => {
2051                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
2052                }
2053                _ => None,
2054            })
2055        })
2056    }
2057
2058    pub(crate) fn parse_builtin<T>(
2059        &mut self,
2060        parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
2061    ) -> PResult<'a, T> {
2062        let lo = self.token.span;
2063
2064        self.bump(); // `builtin`
2065        self.bump(); // `#`
2066
2067        let Some((ident, IdentIsRaw::No)) = self.token.ident() else {
2068            let err =
2069                self.dcx().create_err(diagnostics::ExpectedBuiltinIdent { span: self.token.span });
2070            return Err(err);
2071        };
2072        self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);
2073        self.bump();
2074
2075        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
2076        let ret = if let Some(res) = parse(self, lo, ident)? {
2077            Ok(res)
2078        } else {
2079            let err = self.dcx().create_err(diagnostics::UnknownBuiltinConstruct {
2080                span: lo.to(ident.span),
2081                name: ident,
2082            });
2083            return Err(err);
2084        };
2085        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
2086
2087        ret
2088    }
2089
2090    /// Built-in macro for `offset_of!` expressions.
2091    pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2092        let container = self.parse_ty()?;
2093        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
2094
2095        let fields = self.parse_floating_field_access()?;
2096        let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
2097
2098        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)]) {
2099            if trailing_comma {
2100                e.note("unexpected third argument to offset_of");
2101            } else {
2102                e.note("offset_of expects dot-separated field and variant names");
2103            }
2104            e.emit();
2105        }
2106
2107        // Eat tokens until the macro call ends.
2108        if self.may_recover() {
2109            while !self.token.kind.is_close_delim_or_eof() {
2110                self.bump();
2111            }
2112        }
2113
2114        let span = lo.to(self.token.span);
2115        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
2116    }
2117
2118    /// Built-in macro for type ascription expressions.
2119    pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2120        let expr = self.parse_expr()?;
2121        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
2122        let ty = self.parse_ty()?;
2123        let span = lo.to(self.token.span);
2124        Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
2125    }
2126
2127    pub(crate) fn parse_expr_unsafe_binder_cast(
2128        &mut self,
2129        lo: Span,
2130        kind: UnsafeBinderCastKind,
2131    ) -> PResult<'a, Box<Expr>> {
2132        let expr = self.parse_expr()?;
2133        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 };
2134        let span = lo.to(self.token.span);
2135        Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
2136    }
2137
2138    /// Returns a string literal if the next token is a string literal.
2139    /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
2140    /// and returns `None` if the next token is not literal at all.
2141    pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {
2142        match self.parse_opt_meta_item_lit() {
2143            Some(lit) => match lit.kind {
2144                ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
2145                    style,
2146                    symbol: lit.symbol,
2147                    suffix: lit.suffix,
2148                    span: lit.span,
2149                    symbol_unescaped,
2150                }),
2151                _ => Err(Some(lit)),
2152            },
2153            None => Err(None),
2154        }
2155    }
2156
2157    pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
2158        (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
2159    }
2160
2161    fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
2162        ast::MetaItemLit {
2163            symbol: name,
2164            suffix: None,
2165            kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
2166            span,
2167        }
2168    }
2169
2170    fn handle_missing_lit<L>(
2171        &mut self,
2172        mk_lit_char: impl FnOnce(Symbol, Span) -> L,
2173    ) -> PResult<'a, L> {
2174        let token = self.token;
2175        let err = |self_: &Self| {
2176            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));
2177            self_.dcx().struct_span_err(token.span, msg)
2178        };
2179        // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that
2180        // makes sense.
2181        if let Some((ident, IdentIsRaw::No)) = self.token.lifetime()
2182            && could_be_unclosed_char_literal(ident)
2183        {
2184            let lt = self.expect_lifetime();
2185            Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
2186        } else {
2187            Err(err(self))
2188        }
2189    }
2190
2191    pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
2192        self.parse_opt_token_lit()
2193            .ok_or(())
2194            .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
2195    }
2196
2197    pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
2198        self.parse_opt_meta_item_lit()
2199            .ok_or(())
2200            .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
2201    }
2202
2203    fn recover_after_dot(&mut self) {
2204        if self.token == token::Dot {
2205            // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
2206            // dot would follow an optional literal, so we do this unconditionally.
2207            let recovered = self.look_ahead(1, |next_token| {
2208                // If it's an integer that looks like a float, then recover as such.
2209                //
2210                // We will never encounter the exponent part of a floating
2211                // point literal here, since there's no use of the exponent
2212                // syntax that also constitutes a valid integer, so we need
2213                // not check for that.
2214                if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
2215                    next_token.kind
2216                    && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
2217                    && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
2218                    && self.token.span.hi() == next_token.span.lo()
2219                {
2220                    let s = String::from("0.") + symbol.as_str();
2221                    let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
2222                    Some(Token::new(kind, self.token.span.to(next_token.span)))
2223                } else {
2224                    None
2225                }
2226            });
2227            if let Some(recovered) = recovered {
2228                self.dcx().emit_err(diagnostics::FloatLiteralRequiresIntegerPart {
2229                    span: recovered.span,
2230                    suggestion: recovered.span.shrink_to_lo(),
2231                });
2232                self.bump();
2233                self.token = recovered;
2234            }
2235        }
2236    }
2237
2238    /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and
2239    /// `Lit::from_token` (excluding unary negation).
2240    pub fn eat_token_lit(&mut self) -> Option<token::Lit> {
2241        let check_expr = |expr: Box<Expr>| {
2242            if let ast::ExprKind::Lit(token_lit) = expr.kind {
2243                Some(token_lit)
2244            } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
2245                && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
2246            {
2247                None
2248            } else {
2249                {
    ::core::panicking::panic_fmt(format_args!("unexpected reparsed expr/literal: {0:?}",
            expr.kind));
};panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
2250            }
2251        };
2252        match self.token.uninterpolate().kind {
2253            token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => {
2254                self.bump();
2255                Some(token::Lit::new(token::Bool, name, None))
2256            }
2257            token::Literal(token_lit) => {
2258                self.bump();
2259                Some(token_lit)
2260            }
2261            token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
2262                let lit = self
2263                    .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2264                    .expect("metavar seq literal");
2265                check_expr(lit)
2266            }
2267            token::OpenInvisible(InvisibleOrigin::MetaVar(
2268                mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
2269            )) => {
2270                let expr = self
2271                    .eat_metavar_seq(mv_kind, |this| this.parse_expr())
2272                    .expect("metavar seq expr");
2273                check_expr(expr)
2274            }
2275            _ => None,
2276        }
2277    }
2278
2279    /// Matches `lit = true | false | token_lit`.
2280    /// Returns `None` if the next token is not a literal.
2281    fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> {
2282        self.recover_after_dot();
2283        let span = self.token.span;
2284        self.eat_token_lit().map(|token_lit| (token_lit, span))
2285    }
2286
2287    /// Matches `lit = true | false | token_lit`.
2288    /// Returns `None` if the next token is not a literal.
2289    fn parse_opt_meta_item_lit(&mut self) -> Option<MetaItemLit> {
2290        self.recover_after_dot();
2291        let span = self.token.span;
2292        let uninterpolated_span = self.token_uninterpolated_span();
2293        self.eat_token_lit().map(|token_lit| {
2294            match MetaItemLit::from_token_lit(token_lit, span) {
2295                Ok(lit) => lit,
2296                Err(err) => {
2297                    let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span);
2298                    // Pack possible quotes and prefixes from the original literal into
2299                    // the error literal's symbol so they can be pretty-printed faithfully.
2300                    let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
2301                    let symbol = Symbol::intern(&suffixless_lit.to_string());
2302                    let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
2303                    MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
2304                }
2305            }
2306        })
2307    }
2308
2309    /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
2310    /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
2311    pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> {
2312        if let Some(expr) = self.eat_metavar_seq_with_matcher(
2313            |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
    MetaVarKind::Expr { .. } => true,
    _ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
2314            |this| {
2315                // FIXME(nnethercote) The `expr` case should only match if
2316                // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing
2317                // an `UnOp::Neg` and an `ExprKind::Lit`, like how
2318                // `can_begin_literal_maybe_minus` works. But this method has
2319                // been over-accepting for a long time, and to make that change
2320                // here requires also changing some `parse_literal_maybe_minus`
2321                // call sites to accept additional expression kinds. E.g.
2322                // `ExprKind::Path` must be accepted when parsing range
2323                // patterns. That requires some care. So for now, we continue
2324                // being less strict here than we should be.
2325                this.parse_expr()
2326            },
2327        ) {
2328            return Ok(expr);
2329        } else if let Some(lit) =
2330            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2331        {
2332            return Ok(lit);
2333        }
2334
2335        let lo = self.token.span;
2336        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));
2337        let (token_lit, span) = self.parse_token_lit()?;
2338        let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
2339
2340        if minus_present {
2341            Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
2342        } else {
2343            Ok(expr)
2344        }
2345    }
2346
2347    fn is_array_like_block(&mut self) -> bool {
2348        self.token.kind == TokenKind::OpenBrace
2349            && self
2350                .look_ahead(1, |t| #[allow(non_exhaustive_omitted_patterns)] match t.kind {
    TokenKind::Ident(..) | TokenKind::Literal(_) => true,
    _ => false,
}matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
2351            && self.look_ahead(2, |t| t == &token::Comma)
2352            && self.look_ahead(3, |t| t.can_begin_expr())
2353    }
2354
2355    /// Emits a suggestion if it looks like the user meant an array but
2356    /// accidentally used braces, causing the code to be interpreted as a block
2357    /// expression.
2358    fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<Box<Expr>> {
2359        let mut snapshot = self.create_snapshot_for_diagnostic();
2360        match snapshot.parse_expr_array_or_repeat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
2361            Ok(arr) => {
2362                let guar = self.dcx().emit_err(diagnostics::ArrayBracketsInsteadOfBraces {
2363                    span: arr.span,
2364                    sub: diagnostics::ArrayBracketsInsteadOfBracesSugg {
2365                        left: lo,
2366                        right: snapshot.prev_token.span,
2367                    },
2368                });
2369
2370                self.restore_snapshot(snapshot);
2371                Some(self.mk_expr_err(arr.span, guar))
2372            }
2373            Err(e) => {
2374                e.cancel();
2375                None
2376            }
2377        }
2378    }
2379
2380    fn suggest_missing_semicolon_before_array(
2381        &self,
2382        prev_span: Span,
2383        open_delim_span: Span,
2384    ) -> PResult<'a, ()> {
2385        if !self.may_recover() {
2386            return Ok(());
2387        }
2388
2389        if self.token == token::Comma {
2390            if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
2391                return Ok(());
2392            }
2393            let mut snapshot = self.create_snapshot_for_diagnostic();
2394            snapshot.bump();
2395            match snapshot.parse_seq_to_before_end(
2396                crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBracket,
    token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket),
2397                SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2398                |p| p.parse_expr(),
2399            ) {
2400                Ok(_)
2401                    // When the close delim is `)`, `token.kind` is expected to be `token::CloseParen`,
2402                    // but the actual `token.kind` is `token::CloseBracket`.
2403                    // This is because the `token.kind` of the close delim is treated as the same as
2404                    // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
2405                    // Therefore, `token.kind` should not be compared here.
2406                    if snapshot
2407                        .span_to_snippet(snapshot.token.span)
2408                        .is_ok_and(|snippet| snippet == "]") =>
2409                {
2410                    return Err(self.dcx().create_err(diagnostics::MissingSemicolonBeforeArray {
2411                        open_delim: open_delim_span,
2412                        semicolon: prev_span.shrink_to_hi(),
2413                    }));
2414                }
2415                Ok(_) => (),
2416                Err(err) => err.cancel(),
2417            }
2418        }
2419        Ok(())
2420    }
2421
2422    /// Parses a block or unsafe block.
2423    pub(super) fn parse_expr_block(
2424        &mut self,
2425        opt_label: Option<Label>,
2426        lo: Span,
2427        blk_mode: BlockCheckMode,
2428    ) -> PResult<'a, Box<Expr>> {
2429        if self.may_recover() && self.is_array_like_block() {
2430            if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
2431                return Ok(arr);
2432            }
2433        }
2434
2435        if self.token.is_metavar_block() {
2436            self.dcx().emit_err(diagnostics::InvalidBlockMacroSegment {
2437                span: self.token.span,
2438                context: lo.to(self.token.span),
2439                wrap: diagnostics::WrapInExplicitBlock {
2440                    lo: self.token.span.shrink_to_lo(),
2441                    hi: self.token.span.shrink_to_hi(),
2442                },
2443            });
2444        }
2445
2446        let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
2447        Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
2448    }
2449
2450    /// Parse a block which takes no attributes and has no label
2451    fn parse_simple_block(&mut self) -> PResult<'a, Box<Expr>> {
2452        let blk = self.parse_block()?;
2453        Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
2454    }
2455
2456    /// Parses a closure expression (e.g., `move |args| expr`).
2457    fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> {
2458        let lo = self.token.span;
2459
2460        let before = self.prev_token;
2461        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)) {
2462            let lo = self.token.span;
2463            let (bound_vars, _) = self.parse_higher_ranked_binder()?;
2464            let span = lo.to(self.prev_token.span);
2465
2466            self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
2467
2468            ClosureBinder::For { span, generic_params: bound_vars }
2469        } else {
2470            ClosureBinder::NotPresent
2471        };
2472
2473        let constness = self.parse_closure_constness();
2474
2475        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)) {
2476            self.psess.gated_spans.gate(sym::coroutines, self.prev_token.span);
2477            Movability::Static
2478        } else {
2479            Movability::Movable
2480        };
2481
2482        let coroutine_kind = if self.token_uninterpolated_span().at_least_rust_2018() {
2483            self.parse_coroutine_kind(Case::Sensitive)
2484        } else {
2485            None
2486        };
2487
2488        if let ClosureBinder::NotPresent = binder
2489            && coroutine_kind.is_some()
2490        {
2491            // coroutine closures and generators can have the same qualifiers, so we might end up
2492            // in here if there is a missing `|` but also no `{`. Adjust the expectations in that case.
2493            self.expected_token_types.insert(TokenType::OpenBrace);
2494        }
2495
2496        let capture_clause = self.parse_capture_clause()?;
2497        let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
2498        let decl_hi = self.prev_token.span;
2499        let mut body = match &fn_decl.output {
2500            // No return type.
2501            FnRetTy::Default(_) => {
2502                let restrictions =
2503                    self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2504                let prev = self.prev_token;
2505                let token = self.token;
2506                match self.parse_expr_res(restrictions) {
2507                    Ok(expr) => expr,
2508                    Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
2509                }
2510            }
2511            // Explicit return type (`->`) needs block `-> T { }`.
2512            FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
2513        };
2514
2515        match coroutine_kind {
2516            Some(CoroutineKind::Async { .. }) => {}
2517            Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
2518                // Feature-gate `gen ||` and `async gen ||` closures.
2519                // FIXME(gen_blocks): This perhaps should be a different gate.
2520                self.psess.gated_spans.gate(sym::gen_blocks, span);
2521            }
2522            None => {}
2523        }
2524
2525        if self.token == TokenKind::Semi
2526            && let Some((Delimiter::Parenthesis, _)) = self.token_cursor.parent_delim_and_span()
2527            && self.may_recover()
2528        {
2529            // It is likely that the closure body is a block but where the
2530            // braces have been removed. We will recover and eat the next
2531            // statements later in the parsing process.
2532            body = self.mk_expr_err(
2533                body.span,
2534                self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
2535            );
2536        }
2537
2538        let body_span = body.span;
2539
2540        let closure = self.mk_expr(
2541            lo.to(body.span),
2542            ExprKind::Closure(Box::new(ast::Closure {
2543                binder,
2544                capture_clause,
2545                constness,
2546                coroutine_kind,
2547                movability,
2548                fn_decl,
2549                body,
2550                fn_decl_span: lo.to(decl_hi),
2551                fn_arg_span,
2552            })),
2553        );
2554
2555        // Disable recovery for closure body
2556        let spans =
2557            ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
2558        self.current_closure = Some(spans);
2559
2560        Ok(closure)
2561    }
2562
2563    /// If an explicit return type is given, require a block to appear (RFC 968).
2564    fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, Box<Expr>> {
2565        if self.may_recover()
2566            && self.token.can_begin_expr()
2567            && self.token.kind != TokenKind::OpenBrace
2568            && !self.token.is_metavar_block()
2569        {
2570            let snapshot = self.create_snapshot_for_diagnostic();
2571            let restrictions =
2572                self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2573            let tok = self.token.clone();
2574            match self.parse_expr_res(restrictions) {
2575                Ok(expr) => {
2576                    let descr = super::token_descr(&tok);
2577                    let mut diag = self
2578                        .dcx()
2579                        .struct_span_err(tok.span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("expected `{{`, found {0}", descr))
    })format!("expected `{{`, found {descr}"));
2580                    diag.span_label(
2581                        ret_span,
2582                        "explicit return type requires closure body to be enclosed in braces",
2583                    );
2584                    diag.multipart_suggestion(
2585                        "wrap the expression in curly braces",
2586                        ::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![
2587                            (expr.span.shrink_to_lo(), "{ ".to_string()),
2588                            (expr.span.shrink_to_hi(), " }".to_string()),
2589                        ],
2590                        Applicability::MachineApplicable,
2591                    );
2592                    diag.emit();
2593                    return Ok(expr);
2594                }
2595                Err(diag) => {
2596                    diag.cancel();
2597                    self.restore_snapshot(snapshot);
2598                }
2599            }
2600        }
2601
2602        let body_lo = self.token.span;
2603        self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2604    }
2605
2606    /// Parses an optional `move` or `use` prefix to a closure-like construct.
2607    fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
2608        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)) {
2609            let move_kw_span = self.prev_token.span;
2610            // Check for `move async` and recover
2611            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)) {
2612                let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2613                Err(self
2614                    .dcx()
2615                    .create_err(diagnostics::AsyncMoveOrderIncorrect { span: move_async_span }))
2616            } else {
2617                Ok(CaptureBy::Value { move_kw: move_kw_span })
2618            }
2619        } 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)) {
2620            let use_kw_span = self.prev_token.span;
2621            self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2622            // Check for `use async` and recover
2623            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)) {
2624                let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2625                Err(self
2626                    .dcx()
2627                    .create_err(diagnostics::AsyncUseOrderIncorrect { span: use_async_span }))
2628            } else {
2629                Ok(CaptureBy::Use { use_kw: use_kw_span })
2630            }
2631        } else {
2632            Ok(CaptureBy::Ref)
2633        }
2634    }
2635
2636    /// Parses the `|arg, arg|` header of a closure.
2637    fn parse_fn_block_decl(&mut self) -> PResult<'a, (Box<FnDecl>, Span)> {
2638        let arg_start = self.token.span.lo();
2639
2640        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)) {
2641            ThinVec::new()
2642        } else {
2643            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Or,
    token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or))?;
2644            let args = self
2645                .parse_seq_to_before_tokens(
2646                    &[crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Or,
    token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)],
2647                    &[&token::OrOr],
2648                    SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2649                    |p| p.parse_fn_block_param(),
2650                )?
2651                .0;
2652            self.expect_or()?;
2653            args
2654        };
2655        let arg_span = self.prev_token.span.with_lo(arg_start);
2656        let output =
2657            self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
2658
2659        Ok((Box::new(FnDecl { inputs, output }), arg_span))
2660    }
2661
2662    /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
2663    fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
2664        let lo = self.token.span;
2665        let attrs = self.parse_outer_attributes()?;
2666        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
2667            let pat = Box::new(this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?);
2668            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)) {
2669                this.parse_ty()?
2670            } else {
2671                this.mk_ty(pat.span, TyKind::Infer)
2672            };
2673
2674            Ok((
2675                Param {
2676                    attrs,
2677                    ty,
2678                    pat,
2679                    span: lo.to(this.prev_token.span),
2680                    id: DUMMY_NODE_ID,
2681                    is_placeholder: false,
2682                },
2683                Trailing::from(this.token == token::Comma),
2684                UsePreAttrPos::No,
2685            ))
2686        })
2687    }
2688
2689    /// Parses an `if` expression (`if` token already eaten).
2690    fn parse_expr_if(&mut self) -> PResult<'a, Box<Expr>> {
2691        let lo = self.prev_token.span;
2692        // Scoping code checks the top level edition of the `if`; let's match it here.
2693        // The `CondChecker` also checks the edition of the `let` itself, just to make sure.
2694        let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2695        let cond = self.parse_expr_cond(let_chains_policy)?;
2696        self.parse_if_after_cond(lo, cond)
2697    }
2698
2699    fn parse_if_after_cond(&mut self, lo: Span, mut cond: Box<Expr>) -> PResult<'a, Box<Expr>> {
2700        let cond_span = cond.span;
2701        // Tries to interpret `cond` as either a missing expression if it's a block,
2702        // or as an unfinished expression if it's a binop and the RHS is a block.
2703        // We could probably add more recoveries here too...
2704        let mut recover_block_from_condition = |this: &mut Self| {
2705            let block = match &mut cond.kind {
2706                ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
2707                    if let ExprKind::Block(_, None) = right.kind =>
2708                {
2709                    let guar = this.dcx().emit_err(diagnostics::IfExpressionMissingThenBlock {
2710                        if_span: lo,
2711                        missing_then_block_sub:
2712                            diagnostics::IfExpressionMissingThenBlockSub::UnfinishedCondition(
2713                                cond_span.shrink_to_lo().to(*binop_span),
2714                            ),
2715                        let_else_sub: None,
2716                    });
2717                    std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
2718                }
2719                ExprKind::Block(_, None) => {
2720                    let guar = this.dcx().emit_err(diagnostics::IfExpressionMissingCondition {
2721                        if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
2722                        block_span: self.psess.source_map().start_point(cond_span),
2723                    });
2724                    std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
2725                }
2726                _ => {
2727                    return None;
2728                }
2729            };
2730            if let ExprKind::Block(block, _) = &block.kind {
2731                Some(block.clone())
2732            } else {
2733                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
2734            }
2735        };
2736        // Parse then block
2737        let thn = if self.token.is_keyword(kw::Else) {
2738            if let Some(block) = recover_block_from_condition(self) {
2739                block
2740            } else {
2741                let let_else_sub = #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
    ExprKind::Let(..) => true,
    _ => false,
}matches!(cond.kind, ExprKind::Let(..))
2742                    .then(|| diagnostics::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
2743
2744                let guar = self.dcx().emit_err(diagnostics::IfExpressionMissingThenBlock {
2745                    if_span: lo,
2746                    missing_then_block_sub:
2747                        diagnostics::IfExpressionMissingThenBlockSub::AddThenBlock(
2748                            cond_span.shrink_to_hi(),
2749                        ),
2750                    let_else_sub,
2751                });
2752                self.mk_block_err(cond_span.shrink_to_hi(), guar)
2753            }
2754        } else {
2755            let attrs = self.parse_outer_attributes()?; // For recovery.
2756            let maybe_fatarrow = self.token;
2757            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)) {
2758                self.parse_block()?
2759            } else if let Some(block) = recover_block_from_condition(self) {
2760                block
2761            } else {
2762                self.error_on_extra_if(&cond)?;
2763                // Parse block, which will always fail, but we can add a nice note to the error
2764                self.parse_block().map_err(|mut err| {
2765                        if self.prev_token == token::Semi
2766                            && self.token == token::AndAnd
2767                            && let maybe_let = self.look_ahead(1, |t| t.clone())
2768                            && maybe_let.is_keyword(kw::Let)
2769                        {
2770                            err.span_suggestion_verbose(
2771                                self.prev_token.span,
2772                                "consider removing this semicolon to parse the `let` as part of the same chain",
2773                                "",
2774                                Applicability::MachineApplicable,
2775                            ).span_note(
2776                                self.token.span.to(maybe_let.span),
2777                                "you likely meant to continue parsing the let-chain starting here",
2778                            );
2779                        } else {
2780                            if self.prev_token == token::Semi
2781                                && (self.token == token::OpenBrace || AssocOp::from_token(&self.token).is_some())
2782                            {
2783                                err.span_suggestion_verbose(
2784                                    self.prev_token.span,
2785                                    "remove this semicolon",
2786                                    "",
2787                                    Applicability::MaybeIncorrect,
2788                                );
2789                            }
2790
2791                            // Look for usages of '=>' where '>=' might be intended
2792                            if maybe_fatarrow == token::FatArrow {
2793                                err.span_suggestion_verbose(
2794                                    maybe_fatarrow.span,
2795                                    "you might have meant to write a \"greater than or equal to\" comparison",
2796                                    ">=",
2797                                    Applicability::MaybeIncorrect,
2798                                );
2799                            }
2800                            err.span_note(
2801                                cond_span,
2802                                "the `if` expression is missing a block after this condition",
2803                            );
2804                        }
2805                        err
2806                    })?
2807            };
2808            self.error_on_if_block_attrs(lo, false, block.span, attrs);
2809            block
2810        };
2811        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 };
2812        Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2813    }
2814
2815    /// Parses the condition of a `if` or `while` expression.
2816    ///
2817    /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
2818    /// i.e. the same span we use to later decide whether the drop behaviour should be that of
2819    /// edition `..=2021` or that of `2024..`.
2820    // Public to use it for custom `if` expressions in rustfmt forks like https://github.com/tucant/rustfmt
2821    pub fn parse_expr_cond(
2822        &mut self,
2823        let_chains_policy: LetChainsPolicy,
2824    ) -> PResult<'a, Box<Expr>> {
2825        let mut cond =
2826            self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET)?;
2827
2828        let mut checker = CondChecker::new(self, let_chains_policy);
2829        checker.visit_expr(&mut cond);
2830        Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2831            self.mk_expr_err(cond.span, guar)
2832        } else {
2833            cond
2834        })
2835    }
2836
2837    /// Parses a `let $pat = $expr` pseudo-expression.
2838    fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
2839        let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2840            let err = diagnostics::ExpectedExpressionFoundLet {
2841                span: self.token.span,
2842                reason: diagnostics::ForbiddenLetReason::OtherForbidden,
2843                missing_let: None,
2844                comparison: None,
2845            };
2846            if self.prev_token == token::Or {
2847                // This was part of a closure, the that part of the parser recover.
2848                return Err(self.dcx().create_err(err));
2849            } else {
2850                Recovered::Yes(self.dcx().emit_err(err))
2851            }
2852        } else {
2853            Recovered::No
2854        };
2855        self.bump(); // Eat `let` token
2856        let lo = self.prev_token.span;
2857        let pat = self.parse_pat_no_top_guard(
2858            None,
2859            RecoverComma::Yes,
2860            RecoverColon::Yes,
2861            CommaRecoveryMode::LikelyTuple,
2862        )?;
2863        if self.token == token::EqEq {
2864            self.dcx().emit_err(diagnostics::ExpectedEqForLetExpr {
2865                span: self.token.span,
2866                sugg_span: self.token.span,
2867            });
2868            self.bump();
2869        } else {
2870            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq))?;
2871        }
2872        let expr = self.parse_expr_assoc(Bound::Excluded(prec_let_scrutinee_needs_par()))?;
2873        let span = lo.to(expr.span);
2874        Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered)))
2875    }
2876
2877    /// Parses an `else { ... }` expression (`else` token already eaten).
2878    fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> {
2879        let else_span = self.prev_token.span; // `else`
2880        let attrs = self.parse_outer_attributes()?; // For recovery.
2881        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)) {
2882            self.parse_expr_if()?
2883        } else if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2884            self.parse_simple_block()?
2885        } else {
2886            let snapshot = self.create_snapshot_for_diagnostic();
2887            let first_tok = super::token_descr(&self.token);
2888            let first_tok_span = self.token.span;
2889            match self.parse_expr() {
2890                Ok(cond)
2891                // Try to guess the difference between a "condition-like" vs
2892                // "statement-like" expression.
2893                //
2894                // We are seeing the following code, in which $cond is neither
2895                // ExprKind::Block nor ExprKind::If (the 2 cases wherein this
2896                // would be valid syntax).
2897                //
2898                //     if ... {
2899                //     } else $cond
2900                //
2901                // If $cond is "condition-like" such as ExprKind::Binary, we
2902                // want to suggest inserting `if`.
2903                //
2904                //     if ... {
2905                //     } else if a == b {
2906                //            ^^
2907                //     }
2908                //
2909                // We account for macro calls that were meant as conditions as well.
2910                //
2911                //     if ... {
2912                //     } else if macro! { foo bar } {
2913                //            ^^
2914                //     }
2915                //
2916                // If $cond is "statement-like" such as ExprKind::While then we
2917                // want to suggest wrapping in braces.
2918                //
2919                //     if ... {
2920                //     } else {
2921                //            ^
2922                //         while true {}
2923                //     }
2924                //     ^
2925                    if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
2926                        && (classify::expr_requires_semi_to_be_stmt(&cond)
2927                            || #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
    ExprKind::MacCall(..) => true,
    _ => false,
}matches!(cond.kind, ExprKind::MacCall(..)))
2928                    =>
2929                {
2930                    self.dcx().emit_err(diagnostics::ExpectedElseBlock {
2931                        first_tok_span,
2932                        first_tok,
2933                        else_span,
2934                        condition_start: cond.span.shrink_to_lo(),
2935                    });
2936                    self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2937                }
2938                Err(e) => {
2939                    e.cancel();
2940                    self.restore_snapshot(snapshot);
2941                    self.parse_simple_block()?
2942                },
2943                Ok(_) => {
2944                    self.restore_snapshot(snapshot);
2945                    self.parse_simple_block()?
2946                },
2947            }
2948        };
2949        self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2950        Ok(expr)
2951    }
2952
2953    fn error_on_if_block_attrs(
2954        &self,
2955        ctx_span: Span,
2956        is_ctx_else: bool,
2957        branch_span: Span,
2958        attrs: AttrWrapper,
2959    ) {
2960        if !attrs.is_empty()
2961            && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2962        {
2963            let attributes = x0.span.until(branch_span);
2964            let last = xn.span;
2965            let ctx = if is_ctx_else { "else" } else { "if" };
2966            self.dcx().emit_err(diagnostics::OuterAttributeNotAllowedOnIfElse {
2967                last,
2968                branch_span,
2969                ctx_span,
2970                ctx: ctx.to_string(),
2971                attributes,
2972            });
2973        }
2974    }
2975
2976    fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> {
2977        if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2978            && let BinOpKind::And = binop
2979            && let ExprKind::If(cond, ..) = &right.kind
2980        {
2981            Err(self.dcx().create_err(diagnostics::UnexpectedIfWithIf(
2982                binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2983            )))
2984        } else {
2985            Ok(())
2986        }
2987    }
2988
2989    // Public to use it for custom `for` expressions in rustfmt forks like https://github.com/tucant/rustfmt
2990    pub fn parse_for_head(&mut self) -> PResult<'a, (Pat, Box<Expr>)> {
2991        let begin_paren = if self.token == token::OpenParen {
2992            // Record whether we are about to parse `for (`.
2993            // This is used below for recovery in case of `for ( $stuff ) $block`
2994            // in which case we will suggest `for $stuff $block`.
2995            let start_span = self.token.span;
2996            let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2997            Some((start_span, left))
2998        } else {
2999            None
3000        };
3001        // Try to parse the pattern `for ($PAT) in $EXPR`.
3002        let pat = match (
3003            self.parse_pat_allow_top_guard(
3004                None,
3005                RecoverComma::Yes,
3006                RecoverColon::Yes,
3007                CommaRecoveryMode::LikelyTuple,
3008            ),
3009            begin_paren,
3010        ) {
3011            (Ok(pat), _) => pat, // Happy path.
3012            (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)) => {
3013                // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
3014                // happen right before the return of this method.
3015                let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL) {
3016                    Ok(expr) => expr,
3017                    Err(expr_err) => {
3018                        // We don't know what followed the `in`, so cancel and bubble up the
3019                        // original error.
3020                        expr_err.cancel();
3021                        return Err(err);
3022                    }
3023                };
3024                return if self.token == token::CloseParen {
3025                    // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
3026                    // parser state and emit a targeted suggestion.
3027                    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];
3028                    let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
3029                    self.bump(); // )
3030                    err.cancel();
3031                    self.dcx().emit_err(diagnostics::ParenthesesInForHead {
3032                        span,
3033                        // With e.g. `for (x) in y)` this would replace `(x) in y)`
3034                        // with `x) in y)` which is syntactically invalid.
3035                        // However, this is prevented before we get here.
3036                        sugg: diagnostics::ParenthesesInForHeadSugg { left, right },
3037                    });
3038                    Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
3039                } else {
3040                    Err(err) // Some other error, bubble up.
3041                };
3042            }
3043            (Err(err), _) => return Err(err), // Some other error, bubble up.
3044        };
3045        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)) {
3046            self.error_missing_in_for_loop();
3047        }
3048        self.check_for_for_in_in_typo(self.prev_token.span);
3049        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3050        Ok((pat, expr))
3051    }
3052
3053    /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
3054    fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3055        let is_await =
3056            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));
3057
3058        if is_await {
3059            self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
3060        }
3061
3062        let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
3063
3064        let (pat, expr) = self.parse_for_head()?;
3065        let pat = Box::new(pat);
3066        // Recover from missing expression in `for` loop
3067        if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    ExprKind::Block(..) => true,
    _ => false,
}matches!(expr.kind, ExprKind::Block(..))
3068            && self.token.kind != token::OpenBrace
3069            && self.may_recover()
3070        {
3071            let guar = self.dcx().emit_err(diagnostics::MissingExpressionInForLoop {
3072                span: expr.span.shrink_to_lo(),
3073            });
3074            let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
3075            let block = self.mk_block(::thin_vec::ThinVec::new()thin_vec![], BlockCheckMode::Default, self.prev_token.span);
3076            return Ok(self.mk_expr(
3077                lo.to(self.prev_token.span),
3078                ExprKind::ForLoop(Box::new(ForLoop {
3079                    pat,
3080                    iter: err_expr,
3081                    body: block,
3082                    label: opt_label,
3083                    kind,
3084                })),
3085            ));
3086        }
3087
3088        let (attrs, loop_block) = self.parse_inner_attrs_and_block(
3089            // Only suggest moving erroneous block label to the loop header
3090            // if there is not already a label there
3091            opt_label.is_none().then_some(lo),
3092        )?;
3093
3094        let kind = ExprKind::ForLoop(Box::new(ForLoop {
3095            pat,
3096            iter: expr,
3097            body: loop_block,
3098            label: opt_label,
3099            kind,
3100        }));
3101
3102        self.recover_loop_else("for", lo)?;
3103
3104        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3105    }
3106
3107    /// Recovers from an `else` clause after a loop (`for...else`, `while...else`)
3108    fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
3109        if self.token.is_keyword(kw::Else) && self.may_recover() {
3110            let else_span = self.token.span;
3111            self.bump();
3112            let else_clause = self.parse_expr_else()?;
3113            self.dcx().emit_err(diagnostics::LoopElseNotSupported {
3114                span: else_span.to(else_clause.span),
3115                loop_kind,
3116                loop_kw,
3117            });
3118        }
3119        Ok(())
3120    }
3121
3122    fn error_missing_in_for_loop(&mut self) {
3123        let (span, sub) = if self.token.is_ident_named(sym::of) {
3124            // Possibly using JS syntax (#75311).
3125            let span = self.token.span;
3126            self.bump();
3127            (span, Some(diagnostics::MissingInInForLoopSub::InNotOf(span)))
3128        } else if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
3129            let span = self.prev_token.span;
3130            (span, Some(diagnostics::MissingInInForLoopSub::InNotEq(span)))
3131        } else {
3132            let span = self.prev_token.span.between(self.token.span);
3133            let sub = (!self.for_loop_head_has_in())
3134                .then_some(diagnostics::MissingInInForLoopSub::AddIn(span));
3135            (span, sub)
3136        };
3137
3138        self.dcx().emit_err(diagnostics::MissingInInForLoop { span, sub });
3139    }
3140
3141    /// Whether the `for` loop header already contains an `in` before its body.
3142    /// If it does, the binding is malformed (e.g. `for i i in 0..10`) rather
3143    /// than missing `in`, so suggesting another `in` would just be invalid too.
3144    fn for_loop_head_has_in(&self) -> bool {
3145        let mut dist = 0;
3146        loop {
3147            let (is_in, is_end) = self.look_ahead(dist, |t| {
3148                (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))
3149            });
3150            if is_in {
3151                return true;
3152            }
3153            if is_end {
3154                return false;
3155            }
3156            dist += 1;
3157        }
3158    }
3159
3160    /// Parses a `while` or `while let` expression (`while` token already eaten).
3161    fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3162        let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3163        let cond = self.parse_expr_cond(policy).map_err(|mut err| {
3164            err.span_label(lo, "while parsing the condition of this `while` expression");
3165            err
3166        })?;
3167        let (attrs, body) = self
3168            .parse_inner_attrs_and_block(
3169                // Only suggest moving erroneous block label to the loop header
3170                // if there is not already a label there
3171                opt_label.is_none().then_some(lo),
3172            )
3173            .map_err(|mut err| {
3174                err.span_label(lo, "while parsing the body of this `while` expression");
3175                err.span_label(cond.span, "this `while` condition successfully parsed");
3176                err
3177            })?;
3178
3179        self.recover_loop_else("while", lo)?;
3180
3181        Ok(self.mk_expr_with_attrs(
3182            lo.to(self.prev_token.span),
3183            ExprKind::While(cond, body, opt_label),
3184            attrs,
3185        ))
3186    }
3187
3188    /// Parses `loop { ... }` (`loop` token already eaten).
3189    fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3190        let loop_span = self.prev_token.span;
3191        let (attrs, body) = self.parse_inner_attrs_and_block(
3192            // Only suggest moving erroneous block label to the loop header
3193            // if there is not already a label there
3194            opt_label.is_none().then_some(lo),
3195        )?;
3196        self.recover_loop_else("loop", lo)?;
3197        Ok(self.mk_expr_with_attrs(
3198            lo.to(self.prev_token.span),
3199            ExprKind::Loop(body, opt_label, loop_span),
3200            attrs,
3201        ))
3202    }
3203
3204    pub(crate) fn eat_label(&mut self) -> Option<Label> {
3205        if let Some((ident, is_raw)) = self.token.lifetime() {
3206            // Disallow `'fn`, but with a better error message than `expect_lifetime`.
3207            if is_raw == IdentIsRaw::No && ident.without_first_quote().is_reserved() {
3208                self.dcx().emit_err(diagnostics::KeywordLabel { span: ident.span });
3209            }
3210
3211            self.bump();
3212            Some(Label { ident })
3213        } else {
3214            None
3215        }
3216    }
3217
3218    /// Parses a `match ... { ... }` expression (`match` token already eaten).
3219    fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> {
3220        let match_span = self.prev_token.span;
3221        let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3222
3223        self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
3224    }
3225
3226    /// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
3227    /// expression. This is after the match token and scrutinee are eaten
3228    fn parse_match_block(
3229        &mut self,
3230        lo: Span,
3231        match_span: Span,
3232        scrutinee: Box<Expr>,
3233        match_kind: MatchKind,
3234    ) -> PResult<'a, Box<Expr>> {
3235        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)) {
3236            if self.token == token::Semi {
3237                e.span_suggestion_short(
3238                    match_span,
3239                    "try removing this `match`",
3240                    "",
3241                    Applicability::MaybeIncorrect, // speculative
3242                );
3243            }
3244            if self.maybe_recover_unexpected_block_label(None) {
3245                e.cancel();
3246                self.bump();
3247            } else {
3248                return Err(e);
3249            }
3250        }
3251        let attrs = self.parse_inner_attributes()?;
3252
3253        let mut arms = ThinVec::new();
3254        while self.token != token::CloseBrace {
3255            match self.parse_arm() {
3256                Ok(arm) => arms.push(arm),
3257                Err(e) => {
3258                    // Recover by skipping to the end of the block.
3259                    let guar = e.emit();
3260                    self.recover_stmt();
3261                    let span = lo.to(self.token.span);
3262                    if self.token == token::CloseBrace {
3263                        self.bump();
3264                    }
3265                    // Always push at least one arm to make the match non-empty
3266                    arms.push(Arm {
3267                        attrs: Default::default(),
3268                        pat: Box::new(self.mk_pat(span, ast::PatKind::Err(guar))),
3269                        guard: None,
3270                        body: Some(self.mk_expr_err(span, guar)),
3271                        span,
3272                        id: DUMMY_NODE_ID,
3273                        is_placeholder: false,
3274                    });
3275                    return Ok(self.mk_expr_with_attrs(
3276                        span,
3277                        ExprKind::Match(scrutinee, arms, match_kind),
3278                        attrs,
3279                    ));
3280                }
3281            }
3282        }
3283        let hi = self.token.span;
3284        self.bump();
3285        Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
3286    }
3287
3288    /// Attempt to recover from match arm body with statements and no surrounding braces.
3289    fn parse_arm_body_missing_braces(
3290        &mut self,
3291        first_expr: &Box<Expr>,
3292        arrow_span: Span,
3293    ) -> Option<(Span, ErrorGuaranteed)> {
3294        if self.token != token::Semi {
3295            return None;
3296        }
3297        let start_snapshot = self.create_snapshot_for_diagnostic();
3298        let semi_sp = self.token.span;
3299        self.bump(); // `;`
3300        let mut stmts =
3301            ::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()))];
3302        let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3303            let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3304
3305            let guar = this.dcx().emit_err(diagnostics::MatchArmBodyWithoutBraces {
3306                statements: span,
3307                arrow: arrow_span,
3308                num_statements: stmts.len(),
3309                sub: if stmts.len() > 1 {
3310                    diagnostics::MatchArmBodyWithoutBracesSugg::AddBraces {
3311                        left: span.shrink_to_lo(),
3312                        right: span.shrink_to_hi(),
3313                        num_statements: stmts.len(),
3314                    }
3315                } else {
3316                    diagnostics::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
3317                },
3318            });
3319            (span, guar)
3320        };
3321        // We might have either a `,` -> `;` typo, or a block without braces. We need
3322        // a more subtle parsing strategy.
3323        loop {
3324            if self.token == token::CloseBrace {
3325                // We have reached the closing brace of the `match` expression.
3326                return Some(err(self, stmts));
3327            }
3328            if self.token == token::Comma {
3329                self.restore_snapshot(start_snapshot);
3330                return None;
3331            }
3332            let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3333            match self.parse_pat_no_top_alt(None, None) {
3334                Ok(_pat) => {
3335                    if self.token == token::FatArrow {
3336                        // Reached arm end.
3337                        self.restore_snapshot(pre_pat_snapshot);
3338                        return Some(err(self, stmts));
3339                    }
3340                }
3341                Err(err) => {
3342                    err.cancel();
3343                }
3344            }
3345
3346            self.restore_snapshot(pre_pat_snapshot);
3347            match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3348                // Consume statements for as long as possible.
3349                Ok(stmt) => {
3350                    stmts.push(stmt);
3351                }
3352                // We couldn't parse either yet another statement missing it's
3353                // enclosing block nor the next arm's pattern or closing brace.
3354                Err(stmt_err) => {
3355                    stmt_err.cancel();
3356                    self.restore_snapshot(start_snapshot);
3357                    break;
3358                }
3359            }
3360        }
3361        None
3362    }
3363
3364    pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3365        let attrs = self.parse_outer_attributes()?;
3366        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3367            let lo = this.token.span;
3368            let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3369            let pat = Box::new(pat);
3370
3371            let span_before_body = this.prev_token.span;
3372            let arm_body;
3373            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));
3374            let is_almost_fat_arrow =
3375                TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3376
3377            // this avoids the compiler saying that a `,` or `}` was expected even though
3378            // the pattern isn't a never pattern (and thus an arm body is required)
3379            let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3380                || #[allow(non_exhaustive_omitted_patterns)] match this.token.kind {
    token::Comma | token::CloseBrace => true,
    _ => false,
}matches!(this.token.kind, token::Comma | token::CloseBrace);
3381
3382            let mut result = if armless {
3383                // A pattern without a body, allowed for never patterns.
3384                arm_body = None;
3385                let span = lo.to(this.prev_token.span);
3386                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| {
3387                    // Don't gate twice
3388                    if !pat.contains_never_pattern() {
3389                        this.psess.gated_spans.gate(sym::never_patterns, span);
3390                    }
3391                    x
3392                })
3393            } else {
3394                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)) {
3395                    // We might have a `=>` -> `=` or `->` typo (issue #89396).
3396                    if is_almost_fat_arrow {
3397                        err.span_suggestion_verbose(
3398                            this.token.span,
3399                            "use a fat arrow to start a match arm",
3400                            "=>",
3401                            Applicability::MachineApplicable,
3402                        );
3403                        if #[allow(non_exhaustive_omitted_patterns)] match (&this.prev_token.kind,
        &this.token.kind) {
    (token::DotDotEq, token::Gt) => true,
    _ => false,
}matches!(
3404                            (&this.prev_token.kind, &this.token.kind),
3405                            (token::DotDotEq, token::Gt)
3406                        ) {
3407                            // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
3408                            // so we suppress the error here
3409                            err.delay_as_bug();
3410                        } else {
3411                            err.emit();
3412                        }
3413                        this.bump();
3414                    } else {
3415                        return Err(err);
3416                    }
3417                }
3418                let arrow_span = this.prev_token.span;
3419                let arm_start_span = this.token.span;
3420
3421                let expr =
3422                    this.parse_expr_res(Restrictions::STMT_EXPR).map_err(|mut err| {
3423                        err.span_label(arrow_span, "while parsing the `match` arm starting here");
3424                        err
3425                    })?;
3426
3427                let require_comma =
3428                    !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3429
3430                if !require_comma {
3431                    arm_body = Some(expr);
3432                    // Eat a comma if it exists, though.
3433                    let _ = this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3434                    Ok(Recovered::No)
3435                } else if let Some((span, guar)) =
3436                    this.parse_arm_body_missing_braces(&expr, arrow_span)
3437                {
3438                    let body = this.mk_expr_err(span, guar);
3439                    arm_body = Some(body);
3440                    Ok(Recovered::Yes(guar))
3441                } else {
3442                    let expr_span = expr.span;
3443                    arm_body = Some(expr);
3444                    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| {
3445                        if this.token == token::FatArrow {
3446                            let sm = this.psess.source_map();
3447                            if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3448                                && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3449                                && expr_lines.lines.len() == 2
3450                            {
3451                                if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3452                                    // We check whether there's any trailing code in the parse span,
3453                                    // if there isn't, we very likely have the following:
3454                                    //
3455                                    // X |     &Y => "y"
3456                                    //   |        --    - missing comma
3457                                    //   |        |
3458                                    //   |        arrow_span
3459                                    // X |     &X => "x"
3460                                    //   |      - ^^ self.token.span
3461                                    //   |      |
3462                                    //   |      parsed until here as `"y" & X`
3463                                    err.span_suggestion_short(
3464                                        arm_start_span.shrink_to_hi(),
3465                                        "missing a comma here to end this `match` arm",
3466                                        ",",
3467                                        Applicability::MachineApplicable,
3468                                    );
3469                                } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3470                                    == expr_lines.lines[0].end_col
3471                                {
3472                                    // similar to the above, but we may typo a `.` or `/` at the end of the line
3473                                    let comma_span = arm_start_span
3474                                        .shrink_to_hi()
3475                                        .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3476                                    if let Ok(res) = sm.span_to_snippet(comma_span)
3477                                        && (res == "." || res == "/")
3478                                    {
3479                                        err.span_suggestion_short(
3480                                            comma_span,
3481                                            "you might have meant to write a `,` to end this `match` arm",
3482                                            ",",
3483                                            Applicability::MachineApplicable,
3484                                        );
3485                                    }
3486                                }
3487                            }
3488                        } else {
3489                            err.span_label(
3490                                arrow_span,
3491                                "while parsing the `match` arm starting here",
3492                            );
3493                        }
3494                        err
3495                    })
3496                }
3497            };
3498
3499            let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3500            let arm_span = lo.to(hi_span);
3501
3502            // We want to recover:
3503            // X |     Some(_) => foo()
3504            //   |                     - missing comma
3505            // X |     None => "x"
3506            //   |     ^^^^ self.token.span
3507            // as well as:
3508            // X |     Some(!)
3509            //   |            - missing comma
3510            // X |     None => "x"
3511            //   |     ^^^^ self.token.span
3512            // But we musn't recover
3513            // X |     pat[0] => {}
3514            //   |        ^ self.token.span
3515            let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3516            if recover_missing_comma {
3517                result = result.or_else(|err| {
3518                    // FIXME(compiler-errors): We could also recover `; PAT =>` here
3519
3520                    // Try to parse a following `PAT =>`, if successful
3521                    // then we should recover.
3522                    let mut snapshot = this.create_snapshot_for_diagnostic();
3523                    let pattern_follows = snapshot
3524                        .parse_pat_no_top_guard(
3525                            None,
3526                            RecoverComma::Yes,
3527                            RecoverColon::Yes,
3528                            CommaRecoveryMode::EitherTupleOrPipe,
3529                        )
3530                        .map_err(|err| err.cancel())
3531                        .is_ok();
3532                    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)) {
3533                        err.cancel();
3534                        let guar = this.dcx().emit_err(diagnostics::MissingCommaAfterMatchArm {
3535                            span: arm_span.shrink_to_hi(),
3536                        });
3537                        return Ok(Recovered::Yes(guar));
3538                    }
3539                    Err(err)
3540                });
3541            }
3542            result?;
3543
3544            Ok((
3545                ast::Arm {
3546                    attrs,
3547                    pat,
3548                    guard,
3549                    body: arm_body,
3550                    span: arm_span,
3551                    id: DUMMY_NODE_ID,
3552                    is_placeholder: false,
3553                },
3554                Trailing::No,
3555                UsePreAttrPos::No,
3556            ))
3557        })
3558    }
3559
3560    pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
3561        self.eat_metavar_seq(MetaVarKind::Guard, |this| {
3562            this.expect_match_arm_guard(ForceCollect::Yes)
3563        })
3564    }
3565
3566    fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
3567        if let Some(guard) = self.eat_metavar_guard() {
3568            return Ok(Some(guard));
3569        }
3570
3571        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)) {
3572            // No match arm guard present.
3573            return Ok(None);
3574        }
3575        self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
3576    }
3577
3578    pub(crate) fn expect_match_arm_guard(
3579        &mut self,
3580        force_collect: ForceCollect,
3581    ) -> PResult<'a, Box<Guard>> {
3582        if let Some(guard) = self.eat_metavar_guard() {
3583            return Ok(guard);
3584        }
3585
3586        self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::If,
    token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If))?;
3587        self.expect_match_arm_guard_cond(force_collect)
3588    }
3589
3590    fn expect_match_arm_guard_cond(
3591        &mut self,
3592        force_collect: ForceCollect,
3593    ) -> PResult<'a, Box<Guard>> {
3594        let leading_if_span = self.prev_token.span;
3595
3596        let mut cond = self.parse_match_guard_condition(force_collect)?;
3597        let cond_span = cond.span;
3598
3599        CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3600
3601        let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
3602        Ok(Box::new(guard))
3603    }
3604
3605    fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
3606        if self.token == token::OpenParen {
3607            let left = self.token.span;
3608            let pat = self.parse_pat_no_top_guard(
3609                None,
3610                RecoverComma::Yes,
3611                RecoverColon::Yes,
3612                CommaRecoveryMode::EitherTupleOrPipe,
3613            )?;
3614            if let ast::PatKind::Paren(subpat) = &pat.kind
3615                && let ast::PatKind::Guard(..) = &subpat.kind
3616            {
3617                // Detect and recover from `($pat if $cond) => $arm`.
3618                // FIXME(guard_patterns): convert this to a normal guard instead
3619                let span = pat.span;
3620                let ast::PatKind::Paren(subpat) = pat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3621                let ast::PatKind::Guard(_, mut guard) = subpat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3622                self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
3623                let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3624                checker.visit_expr(&mut guard.cond);
3625
3626                let right = self.prev_token.span;
3627                self.dcx().emit_err(diagnostics::ParenthesesInMatchPat {
3628                    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],
3629                    sugg: diagnostics::ParenthesesInMatchPatSugg { left, right },
3630                });
3631
3632                if let Some(guar) = checker.found_incorrect_let_chain {
3633                    guard.cond = *self.mk_expr_err(guard.span(), guar);
3634                }
3635                Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
3636            } else {
3637                Ok((pat, self.parse_match_arm_guard()?))
3638            }
3639        } else {
3640            // Regular parser flow:
3641            let pat = self.parse_pat_no_top_guard(
3642                None,
3643                RecoverComma::Yes,
3644                RecoverColon::Yes,
3645                CommaRecoveryMode::EitherTupleOrPipe,
3646            )?;
3647            Ok((pat, self.parse_match_arm_guard()?))
3648        }
3649    }
3650
3651    fn parse_match_guard_condition(
3652        &mut self,
3653        force_collect: ForceCollect,
3654    ) -> PResult<'a, Box<Expr>> {
3655        let attrs = self.parse_outer_attributes()?;
3656        let expr = self.collect_tokens(
3657            None,
3658            AttrWrapper::empty(),
3659            force_collect,
3660            |this, _empty_attrs| {
3661                match this.parse_expr_res_after_attrs(
3662                    Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD,
3663                    attrs,
3664                ) {
3665                    Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
3666                    Err(mut err) => {
3667                        if this.prev_token == token::OpenBrace {
3668                            let sugg_sp = this.prev_token.span.shrink_to_lo();
3669                            // Consume everything within the braces, let's avoid further parse
3670                            // errors.
3671                            this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3672                            let msg =
3673                                "you might have meant to start a match arm after the match guard";
3674                            if this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
3675                                let applicability = if this.token != token::FatArrow {
3676                                    // We have high confidence that we indeed didn't have a struct
3677                                    // literal in the match guard, but rather we had some operation
3678                                    // that ended in a path, immediately followed by a block that was
3679                                    // meant to be the match arm.
3680                                    Applicability::MachineApplicable
3681                                } else {
3682                                    Applicability::MaybeIncorrect
3683                                };
3684                                err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3685                            }
3686                        }
3687                        Err(err)
3688                    }
3689                }
3690            },
3691        )?;
3692        Ok(expr)
3693    }
3694
3695    pub(crate) fn is_builtin(&self) -> bool {
3696        self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
3697    }
3698
3699    /// Parses a `try {...}` or `try bikeshed Ty {...}` expression (`try` token already eaten).
3700    fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> {
3701        let annotation =
3702            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 };
3703
3704        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3705        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)) {
3706            Err(self.dcx().create_err(diagnostics::CatchAfterTry { span: self.prev_token.span }))
3707        } else {
3708            let span = span_lo.to(body.span);
3709            let gate_sym =
3710                if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous };
3711            self.psess.gated_spans.gate(gate_sym, span);
3712            Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs))
3713        }
3714    }
3715
3716    fn is_do_catch_block(&self) -> bool {
3717        self.token.is_keyword(kw::Do)
3718            && self.is_keyword_ahead(1, &[kw::Catch])
3719            && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3720            && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3721    }
3722
3723    fn is_do_yeet(&self) -> bool {
3724        self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3725    }
3726
3727    fn is_try_block(&self) -> bool {
3728        self.token.is_keyword(kw::Try)
3729            && self.look_ahead(1, |t| {
3730                *t == token::OpenBrace
3731                    || t.is_metavar_block()
3732                    || t.kind == TokenKind::Ident(sym::bikeshed, IdentIsRaw::No)
3733            })
3734            && self.token_uninterpolated_span().at_least_rust_2018()
3735    }
3736
3737    /// Parses an `async move? {...}` or `gen move? {...}` expression.
3738    fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> {
3739        let lo = self.token.span;
3740        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)) {
3741            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)) { GenBlockKind::AsyncGen } else { GenBlockKind::Async }
3742        } else {
3743            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)));
3744            GenBlockKind::Gen
3745        };
3746        match kind {
3747            GenBlockKind::Async => {
3748                // `async` blocks are stable
3749            }
3750            GenBlockKind::Gen | GenBlockKind::AsyncGen => {
3751                self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3752            }
3753        }
3754        let capture_clause = self.parse_capture_clause()?;
3755        let decl_span = lo.to(self.prev_token.span);
3756        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3757        let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3758        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3759    }
3760
3761    fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3762        self.is_keyword_ahead(lookahead, &[kw])
3763            && ((
3764                // `async move {`
3765                self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3766                    && self.look_ahead(lookahead + 2, |t| {
3767                        *t == token::OpenBrace || t.is_metavar_block()
3768                    })
3769            ) || (
3770                // `async {`
3771                self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3772            ))
3773    }
3774
3775    pub(super) fn is_async_gen_block(&self) -> bool {
3776        self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3777    }
3778
3779    fn is_likely_struct_lit(&self) -> bool {
3780        // `{ ident, ` and `{ ident: ` cannot start a block.
3781        self.look_ahead(1, |t| t.is_ident())
3782            && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3783    }
3784
3785    fn maybe_parse_struct_expr(
3786        &mut self,
3787        qself: &Option<Box<ast::QSelf>>,
3788        path: &ast::Path,
3789    ) -> Option<PResult<'a, Box<Expr>>> {
3790        let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3791        match (struct_allowed, self.is_likely_struct_lit()) {
3792            // A struct literal isn't expected and one is pretty much assured not to be present. The
3793            // only situation that isn't detected is when a struct with a single field was attempted
3794            // in a place where a struct literal wasn't expected, but regular parser errors apply.
3795            // Happy path.
3796            (false, false) => None,
3797            (true, _) => {
3798                // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for
3799                // any kind of recovery. Happy path.
3800                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)) {
3801                    return Some(Err(err));
3802                }
3803                Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
3804            }
3805            (false, true) => {
3806                // We have something like `match foo { bar,` or `match foo { bar:`, which means the
3807                // user might have meant to write a struct literal as part of the `match`
3808                // discriminant. This is done purely for error recovery.
3809                let snapshot = self.create_snapshot_for_diagnostic();
3810                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)) {
3811                    return Some(Err(err));
3812                }
3813                match self.parse_expr_struct(qself.clone(), path.clone(), false) {
3814                    Ok(expr) => {
3815                        // This is a struct literal, but we don't accept them here.
3816                        self.dcx().emit_err(diagnostics::StructLiteralNotAllowedHere {
3817                            span: expr.span,
3818                            sub: diagnostics::StructLiteralNotAllowedHereSugg {
3819                                left: path.span.shrink_to_lo(),
3820                                right: expr.span.shrink_to_hi(),
3821                            },
3822                        });
3823                        Some(Ok(expr))
3824                    }
3825                    Err(err) => {
3826                        // We couldn't parse a valid struct, rollback and let the parser emit an
3827                        // error elsewhere.
3828                        err.cancel();
3829                        self.restore_snapshot(snapshot);
3830                        None
3831                    }
3832                }
3833            }
3834        }
3835    }
3836
3837    fn maybe_recover_bad_struct_literal_path(
3838        &mut self,
3839        is_underscore_entry_point: bool,
3840    ) -> PResult<'a, Option<Box<Expr>>> {
3841        if self.may_recover()
3842            && self.check_noexpect(&token::OpenBrace)
3843            && (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3844                && self.is_likely_struct_lit())
3845        {
3846            let span = if is_underscore_entry_point {
3847                self.prev_token.span
3848            } else {
3849                self.token.span.shrink_to_lo()
3850            };
3851
3852            self.bump(); // {
3853            let expr = self.parse_expr_struct(
3854                None,
3855                Path::from_ident(Ident::new(kw::Underscore, span)),
3856                false,
3857            )?;
3858
3859            let guar = if is_underscore_entry_point {
3860                self.dcx().create_err(diagnostics::StructLiteralPlaceholderPath { span }).emit()
3861            } else {
3862                self.dcx()
3863                    .create_err(diagnostics::StructLiteralWithoutPathLate {
3864                        span: expr.span,
3865                        suggestion_span: expr.span.shrink_to_lo(),
3866                    })
3867                    .emit()
3868            };
3869
3870            Ok(Some(self.mk_expr_err(expr.span, guar)))
3871        } else {
3872            Ok(None)
3873        }
3874    }
3875
3876    pub(super) fn parse_struct_fields(
3877        &mut self,
3878        pth: ast::Path,
3879        recover: bool,
3880        close: ExpTokenPair,
3881    ) -> PResult<
3882        'a,
3883        (
3884            ThinVec<ExprField>,
3885            ast::StructRest,
3886            Option<ErrorGuaranteed>, /* async blocks are forbidden in Rust 2015 */
3887        ),
3888    > {
3889        let mut fields = ThinVec::new();
3890        let mut base = ast::StructRest::None;
3891        let mut recovered_async = None;
3892        let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3893
3894        let async_block_err = |e: &mut Diag<'_>, span: Span| {
3895            diagnostics::AsyncBlockIn2015 { span }.add_to_diag(e);
3896            diagnostics::HelpUseLatestEdition::new().add_to_diag(e);
3897        };
3898
3899        while self.token != close.tok {
3900            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) {
3901                let exp_span = self.prev_token.span;
3902                // We permit `.. }` on the left-hand side of a destructuring assignment.
3903                if self.check(close) {
3904                    base = ast::StructRest::Rest(self.prev_token.span);
3905                    break;
3906                }
3907                match self.parse_expr() {
3908                    Ok(e) => base = ast::StructRest::Base(e),
3909                    Err(e) if recover => {
3910                        e.emit();
3911                        self.recover_stmt();
3912                    }
3913                    Err(e) => return Err(e),
3914                }
3915                self.recover_struct_comma_after_dotdot(exp_span);
3916                break;
3917            }
3918
3919            // Peek the field's ident before parsing its expr in order to emit better diagnostics.
3920            let peek = self
3921                .token
3922                .ident()
3923                .filter(|(ident, is_raw)| {
3924                    (!ident.is_reserved() || #[allow(non_exhaustive_omitted_patterns)] match is_raw {
    IdentIsRaw::Yes => true,
    _ => false,
}matches!(is_raw, IdentIsRaw::Yes))
3925                        && self.look_ahead(1, |tok| *tok == token::Colon)
3926                })
3927                .map(|(ident, _)| ident);
3928
3929            // We still want a field even if its expr didn't parse.
3930            let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3931                peek.map(|ident| {
3932                    let span = ident.span;
3933                    ExprField {
3934                        ident,
3935                        span,
3936                        expr: this.mk_expr_err(span, guar),
3937                        is_shorthand: false,
3938                        attrs: AttrVec::new(),
3939                        id: DUMMY_NODE_ID,
3940                        is_placeholder: false,
3941                    }
3942                })
3943            };
3944
3945            let parsed_field = match self.parse_expr_field() {
3946                Ok(f) => Ok(f),
3947                Err(mut e) => {
3948                    if pth == kw::Async {
3949                        async_block_err(&mut e, pth.span);
3950                    } else {
3951                        e.span_label(pth.span, "while parsing this struct");
3952                    }
3953
3954                    if let Some((ident, _)) = self.token.ident()
3955                        && !self.token.is_reserved_ident()
3956                        && self.look_ahead(1, |t| {
3957                            AssocOp::from_token(t).is_some()
3958                                || #[allow(non_exhaustive_omitted_patterns)] match t.kind {
    token::OpenParen | token::OpenBracket | token::OpenBrace => true,
    _ => false,
}matches!(
3959                                    t.kind,
3960                                    token::OpenParen | token::OpenBracket | token::OpenBrace
3961                                )
3962                                || *t == token::Dot
3963                        })
3964                    {
3965                        // Looks like they tried to write a shorthand, complex expression,
3966                        // E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
3967                        e.span_suggestion_verbose(
3968                            self.token.span.shrink_to_lo(),
3969                            "try naming a field",
3970                            &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: ",),
3971                            Applicability::MaybeIncorrect,
3972                        );
3973                    }
3974                    if in_if_guard && close.token_type == TokenType::CloseBrace {
3975                        return Err(e);
3976                    }
3977
3978                    if !recover {
3979                        return Err(e);
3980                    }
3981
3982                    let guar = e.emit();
3983                    if pth == kw::Async {
3984                        recovered_async = Some(guar);
3985                    }
3986
3987                    // If we encountered an error which we are recovering from, treat the struct
3988                    // as if it has a `..` in it, because we don’t know what fields the user
3989                    // might have *intended* it to have.
3990                    //
3991                    // This assignment will be overwritten if we actually parse a `..` later.
3992                    //
3993                    // (Note that this code is duplicated between here and below in comma parsing.
3994                    base = ast::StructRest::NoneWithError(guar);
3995
3996                    // If the next token is a comma, then try to parse
3997                    // what comes next as additional fields, rather than
3998                    // bailing out until next `}`.
3999                    if self.token != token::Comma {
4000                        self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
4001                        if self.token != token::Comma {
4002                            break;
4003                        }
4004                    }
4005
4006                    Err(guar)
4007                }
4008            };
4009
4010            let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
4011            // A shorthand field can be turned into a full field with `:`.
4012            // We should point this out.
4013            self.check_or_expected(!is_shorthand, TokenType::Colon);
4014
4015            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]) {
4016                Ok(_) => {
4017                    if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
4018                    {
4019                        // Only include the field if there's no parse error for the field name.
4020                        fields.push(f);
4021                    }
4022                }
4023                Err(mut e) => {
4024                    if pth == kw::Async {
4025                        async_block_err(&mut e, pth.span);
4026                    } else {
4027                        e.span_label(pth.span, "while parsing this struct");
4028                        if peek.is_some() {
4029                            e.span_suggestion(
4030                                self.prev_token.span.shrink_to_hi(),
4031                                "try adding a comma",
4032                                ",",
4033                                Applicability::MachineApplicable,
4034                            );
4035                        }
4036                    }
4037                    if !recover {
4038                        return Err(e);
4039                    }
4040                    let guar = e.emit();
4041                    if pth == kw::Async {
4042                        recovered_async = Some(guar);
4043                    } else if let Some(f) = field_ident(self, guar) {
4044                        fields.push(f);
4045                    }
4046
4047                    // See comment above on this same assignment inside of field parsing.
4048                    base = ast::StructRest::NoneWithError(guar);
4049
4050                    self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
4051                    let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
4052                }
4053            }
4054        }
4055        Ok((fields, base, recovered_async))
4056    }
4057
4058    /// Precondition: already parsed the '{'.
4059    pub(super) fn parse_expr_struct(
4060        &mut self,
4061        qself: Option<Box<ast::QSelf>>,
4062        pth: ast::Path,
4063        recover: bool,
4064    ) -> PResult<'a, Box<Expr>> {
4065        let lo = pth.span;
4066        let (fields, base, recovered_async) =
4067            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))?;
4068        let span = lo.to(self.token.span);
4069        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
4070        let expr = if let Some(guar) = recovered_async {
4071            ExprKind::Err(guar)
4072        } else {
4073            ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base }))
4074        };
4075        Ok(self.mk_expr(span, expr))
4076    }
4077
4078    fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
4079        if self.token != token::Comma {
4080            return;
4081        }
4082        self.dcx().emit_err(diagnostics::CommaAfterBaseStruct {
4083            span: span.to(self.prev_token.span),
4084            comma: self.token.span,
4085        });
4086        self.recover_stmt();
4087    }
4088
4089    fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
4090        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)) {
4091            // recover from typo of `...`, suggest `..`
4092            let span = self.prev_token.span;
4093            self.dcx().emit_err(diagnostics::MissingDotDot { token_span: span, sugg_span: span });
4094            return true;
4095        }
4096        false
4097    }
4098
4099    /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
4100    fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
4101        // Convert `label` -> `'label`,
4102        // so that nameres doesn't complain about non-existing label
4103        let label = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\'{0}", ident.name))
    })format!("'{}", ident.name);
4104        let ident = Ident::new(Symbol::intern(&label), ident.span);
4105
4106        self.dcx().emit_err(diagnostics::ExpectedLabelFoundIdent {
4107            span: ident.span,
4108            start: ident.span.shrink_to_lo(),
4109        });
4110
4111        Label { ident }
4112    }
4113
4114    /// Parses `ident (COLON expr)?`.
4115    fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
4116        let attrs = self.parse_outer_attributes()?;
4117        self.recover_vcs_conflict_marker();
4118        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4119            let lo = this.token.span;
4120
4121            // Check if a colon exists one ahead. This means we're parsing a fieldname.
4122            let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
4123            // Proactively check whether parsing the field will be incorrect.
4124            let is_wrong = this.token.is_non_reserved_ident()
4125                && !this.look_ahead(1, |t| {
4126                    t == &token::Colon
4127                        || t == &token::Eq
4128                        || t == &token::Comma
4129                        || t == &token::CloseBrace
4130                        || t == &token::CloseParen
4131                });
4132            if is_wrong {
4133                return Err(this.dcx().create_err(diagnostics::ExpectedStructField {
4134                    span: this.look_ahead(1, |t| t.span),
4135                    ident_span: this.token.span,
4136                    token: pprust::token_to_string(&this.look_ahead(1, |t| *t)),
4137                }));
4138            }
4139            let (ident, expr) = if is_shorthand {
4140                // Mimic `x: x` for the `x` field shorthand.
4141                let ident = this.parse_ident_common(false)?;
4142                let path = ast::Path::from_ident(ident);
4143                (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
4144            } else {
4145                let ident = this.parse_field_name()?;
4146                this.error_on_eq_field_init(ident);
4147                this.bump(); // `:`
4148                (ident, this.parse_expr()?)
4149            };
4150
4151            Ok((
4152                ast::ExprField {
4153                    ident,
4154                    span: lo.to(expr.span),
4155                    expr,
4156                    is_shorthand,
4157                    attrs,
4158                    id: DUMMY_NODE_ID,
4159                    is_placeholder: false,
4160                },
4161                Trailing::from(this.token == token::Comma),
4162                UsePreAttrPos::No,
4163            ))
4164        })
4165    }
4166
4167    /// Check for `=`. This means the source incorrectly attempts to
4168    /// initialize a field with an eq rather than a colon.
4169    fn error_on_eq_field_init(&self, field_name: Ident) {
4170        if self.token != token::Eq {
4171            return;
4172        }
4173
4174        self.dcx().emit_err(diagnostics::EqFieldInit {
4175            span: self.token.span,
4176            eq: field_name.span.shrink_to_hi().to(self.token.span),
4177        });
4178    }
4179
4180    fn err_dotdotdot_syntax(&self, span: Span) {
4181        self.dcx().emit_err(diagnostics::DotDotDot { span });
4182    }
4183
4184    fn err_larrow_operator(&self, span: Span) {
4185        self.dcx().emit_err(diagnostics::LeftArrowOperator { span });
4186    }
4187
4188    fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4189        ExprKind::AssignOp(assign_op, lhs, rhs)
4190    }
4191
4192    fn mk_range(
4193        &mut self,
4194        start: Option<Box<Expr>>,
4195        end: Option<Box<Expr>>,
4196        limits: RangeLimits,
4197    ) -> ExprKind {
4198        if end.is_none() && limits == RangeLimits::Closed {
4199            let guar = self.inclusive_range_with_incorrect_end();
4200            ExprKind::Err(guar)
4201        } else {
4202            ExprKind::Range(start, end, limits)
4203        }
4204    }
4205
4206    fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind {
4207        ExprKind::Unary(unop, expr)
4208    }
4209
4210    fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4211        ExprKind::Binary(binop, lhs, rhs)
4212    }
4213
4214    fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind {
4215        ExprKind::Index(expr, idx, brackets_span)
4216    }
4217
4218    fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind {
4219        ExprKind::Call(f, args)
4220    }
4221
4222    fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4223        let span = lo.to(self.prev_token.span);
4224        let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
4225        self.recover_from_await_method_call();
4226        await_expr
4227    }
4228
4229    fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4230        let span = lo.to(self.prev_token.span);
4231        let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
4232        self.recover_from_use();
4233        use_expr
4234    }
4235
4236    pub(crate) fn mk_expr_with_attrs(
4237        &self,
4238        span: Span,
4239        kind: ExprKind,
4240        attrs: AttrVec,
4241    ) -> Box<Expr> {
4242        Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
4243    }
4244
4245    pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> {
4246        self.mk_expr_with_attrs(span, kind, AttrVec::new())
4247    }
4248
4249    pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> {
4250        self.mk_expr(span, ExprKind::Err(guar))
4251    }
4252
4253    pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
4254        self.mk_expr(span, ExprKind::Tup(Default::default()))
4255    }
4256
4257    pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
4258        self.mk_expr(
4259            span,
4260            ast::ExprKind::Closure(Box::new(ast::Closure {
4261                binder: rustc_ast::ClosureBinder::NotPresent,
4262                constness: rustc_ast::Const::No,
4263                movability: rustc_ast::Movability::Movable,
4264                capture_clause: rustc_ast::CaptureBy::Ref,
4265                coroutine_kind: None,
4266                fn_decl: Box::new(rustc_ast::FnDecl {
4267                    inputs: Default::default(),
4268                    output: rustc_ast::FnRetTy::Default(span),
4269                }),
4270                fn_arg_span: span,
4271                fn_decl_span: span,
4272                body,
4273            })),
4274        )
4275    }
4276
4277    /// Create expression span ensuring the span of the parent node
4278    /// is larger than the span of lhs and rhs, including the attributes.
4279    fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
4280        lhs.attrs
4281            .iter()
4282            .find(|a| a.style == AttrStyle::Outer)
4283            .map_or(lhs_span, |a| a.span)
4284            .to(op_span)
4285            .to(rhs_span)
4286    }
4287
4288    fn collect_tokens_for_expr(
4289        &mut self,
4290        attrs: AttrWrapper,
4291        f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>,
4292    ) -> PResult<'a, Box<Expr>> {
4293        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4294            let res = f(this, attrs)?;
4295            let trailing = Trailing::from(
4296                this.restrictions.contains(Restrictions::STMT_EXPR)
4297                     && this.token == token::Semi
4298                // FIXME: pass an additional condition through from the place
4299                // where we know we need a comma, rather than assuming that
4300                // `#[attr] expr,` always captures a trailing comma.
4301                || this.token == token::Comma,
4302            );
4303            Ok((res, trailing, UsePreAttrPos::No))
4304        })
4305    }
4306}
4307
4308/// Could this lifetime/label be an unclosed char literal? For example, `'a`
4309/// could be, but `'abc` could not.
4310pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4311    ident.name.as_str().starts_with('\'')
4312        && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4313}
4314
4315/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
4316/// 2024 and later). In case of edition dependence, specify the currently present edition.
4317pub enum LetChainsPolicy {
4318    AlwaysAllowed,
4319    EditionDependent { current_edition: Edition },
4320}
4321
4322/// Visitor to check for invalid use of `ExprKind::Let` that can't
4323/// easily be caught in parsing. For example:
4324///
4325/// ```rust,ignore (example)
4326/// // Only know that the let isn't allowed once the `||` token is reached
4327/// if let Some(x) = y || true {}
4328/// // Only know that the let isn't allowed once the second `=` token is reached.
4329/// if let Some(x) = y && z = 1 {}
4330/// ```
4331struct CondChecker<'a> {
4332    parser: &'a Parser<'a>,
4333    let_chains_policy: LetChainsPolicy,
4334    depth: u32,
4335    forbid_let_reason: Option<diagnostics::ForbiddenLetReason>,
4336    missing_let: Option<diagnostics::MaybeMissingLet>,
4337    comparison: Option<diagnostics::MaybeComparison>,
4338    found_incorrect_let_chain: Option<ErrorGuaranteed>,
4339}
4340
4341impl<'a> CondChecker<'a> {
4342    fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4343        CondChecker {
4344            parser,
4345            forbid_let_reason: None,
4346            missing_let: None,
4347            comparison: None,
4348            let_chains_policy,
4349            found_incorrect_let_chain: None,
4350            depth: 0,
4351        }
4352    }
4353}
4354
4355impl MutVisitor for CondChecker<'_> {
4356    fn visit_expr(&mut self, e: &mut Expr) {
4357        self.depth += 1;
4358
4359        let span = e.span;
4360        match e.kind {
4361            ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4362                if let Some(reason) = self.forbid_let_reason {
4363                    let error = match reason {
4364                        diagnostics::ForbiddenLetReason::NotSupportedOr(or_span) => {
4365                            self.parser.dcx().emit_err(diagnostics::OrInLetChain { span: or_span })
4366                        }
4367                        _ => {
4368                            let guar = self.parser.dcx().emit_err(
4369                                diagnostics::ExpectedExpressionFoundLet {
4370                                    span,
4371                                    reason,
4372                                    missing_let: self.missing_let,
4373                                    comparison: self.comparison,
4374                                },
4375                            );
4376                            if let Some(_) = self.missing_let {
4377                                self.found_incorrect_let_chain = Some(guar);
4378                            }
4379                            guar
4380                        }
4381                    };
4382                    *recovered = Recovered::Yes(error);
4383                } else if self.depth > 1 {
4384                    // Top level `let` is always allowed; only gate chains
4385                    match self.let_chains_policy {
4386                        LetChainsPolicy::AlwaysAllowed => (),
4387                        LetChainsPolicy::EditionDependent { current_edition } => {
4388                            if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4389                                self.parser.dcx().emit_err(diagnostics::LetChainPre2024 { span });
4390                            }
4391                        }
4392                    }
4393                }
4394            }
4395            ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4396                mut_visit::walk_expr(self, e);
4397            }
4398            ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4399                if let None | Some(diagnostics::ForbiddenLetReason::NotSupportedOr(_)) =
4400                    self.forbid_let_reason =>
4401            {
4402                let forbid_let_reason = self.forbid_let_reason;
4403                self.forbid_let_reason =
4404                    Some(diagnostics::ForbiddenLetReason::NotSupportedOr(or_span));
4405                mut_visit::walk_expr(self, e);
4406                self.forbid_let_reason = forbid_let_reason;
4407            }
4408            ExprKind::Paren(ref inner)
4409                if let None | Some(diagnostics::ForbiddenLetReason::NotSupportedParentheses(_)) =
4410                    self.forbid_let_reason =>
4411            {
4412                let forbid_let_reason = self.forbid_let_reason;
4413                self.forbid_let_reason =
4414                    Some(diagnostics::ForbiddenLetReason::NotSupportedParentheses(inner.span));
4415                mut_visit::walk_expr(self, e);
4416                self.forbid_let_reason = forbid_let_reason;
4417            }
4418            ExprKind::Assign(ref lhs, ref rhs, span) => {
4419                if let ExprKind::Call(_, _) = &lhs.kind {
4420                    fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4421                        fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4422                            match &e.kind {
4423                                ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
4424                                ExprKind::Path(_, path) => Some((depth, path)),
4425                                _ => None,
4426                            }
4427                        }
4428
4429                        inner(e, 0)
4430                    }
4431
4432                    if let Some((depth, path)) = get_path_from_rhs(rhs) {
4433                        // For cases like if Some(_) = x && let Some(_) = y && let Some(_) = z
4434                        // This return let Some(_) = y expression
4435                        fn find_let_some(expr: &Expr) -> Option<&Expr> {
4436                            match &expr.kind {
4437                                ExprKind::Let(..) => Some(expr),
4438
4439                                ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
4440                                    find_let_some(lhs).or_else(|| find_let_some(rhs))
4441                                }
4442
4443                                _ => None,
4444                            }
4445                        }
4446
4447                        let expr_span = lhs.span.to(path.span);
4448
4449                        if let Some(later_rhs) = find_let_some(rhs)
4450                            && depth > 0
4451                        {
4452                            let guar =
4453                                self.parser.dcx().emit_err(diagnostics::LetChainMissingLet {
4454                                    span: lhs.span,
4455                                    label_span: expr_span,
4456                                    rhs_span: later_rhs.span,
4457                                    sug_span: lhs.span.shrink_to_lo(),
4458                                });
4459
4460                            self.found_incorrect_let_chain = Some(guar);
4461                        }
4462                    }
4463                }
4464
4465                let forbid_let_reason = self.forbid_let_reason;
4466                self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4467                let missing_let = self.missing_let;
4468                if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4469                    && let ExprKind::Path(_, _)
4470                    | ExprKind::Struct(_)
4471                    | ExprKind::Call(_, _)
4472                    | ExprKind::Array(_) = rhs.kind
4473                {
4474                    self.missing_let =
4475                        Some(diagnostics::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4476                }
4477                let comparison = self.comparison;
4478                self.comparison = Some(diagnostics::MaybeComparison { span: span.shrink_to_hi() });
4479                mut_visit::walk_expr(self, e);
4480                self.forbid_let_reason = forbid_let_reason;
4481                self.missing_let = missing_let;
4482                self.comparison = comparison;
4483            }
4484            ExprKind::Unary(_, _)
4485            | ExprKind::Await(_, _)
4486            | ExprKind::Move(_, _)
4487            | ExprKind::Use(_, _)
4488            | ExprKind::AssignOp(_, _, _)
4489            | ExprKind::Range(_, _, _)
4490            | ExprKind::Try(_)
4491            | ExprKind::AddrOf(_, _, _)
4492            | ExprKind::Binary(_, _, _)
4493            | ExprKind::Field(_, _)
4494            | ExprKind::Index(_, _, _)
4495            | ExprKind::Call(_, _)
4496            | ExprKind::MethodCall(_)
4497            | ExprKind::Tup(_)
4498            | ExprKind::Paren(_) => {
4499                let forbid_let_reason = self.forbid_let_reason;
4500                self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4501                mut_visit::walk_expr(self, e);
4502                self.forbid_let_reason = forbid_let_reason;
4503            }
4504            ExprKind::Cast(ref mut op, _)
4505            | ExprKind::Type(ref mut op, _)
4506            | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4507                let forbid_let_reason = self.forbid_let_reason;
4508                self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4509                self.visit_expr(op);
4510                self.forbid_let_reason = forbid_let_reason;
4511            }
4512            ExprKind::Let(_, _, _, Recovered::Yes(_))
4513            | ExprKind::Array(_)
4514            | ExprKind::ConstBlock(_)
4515            | ExprKind::Lit(_)
4516            | ExprKind::If(_, _, _)
4517            | ExprKind::While(_, _, _)
4518            | ExprKind::ForLoop { .. }
4519            | ExprKind::Loop(_, _, _)
4520            | ExprKind::Match(_, _, _)
4521            | ExprKind::Closure(_)
4522            | ExprKind::Block(_, _)
4523            | ExprKind::Gen(_, _, _, _)
4524            | ExprKind::TryBlock(_, _)
4525            | ExprKind::Underscore
4526            | ExprKind::Path(_, _)
4527            | ExprKind::Break(_, _)
4528            | ExprKind::Continue(_)
4529            | ExprKind::Ret(_)
4530            | ExprKind::InlineAsm(_)
4531            | ExprKind::OffsetOf(_, _)
4532            | ExprKind::MacCall(_)
4533            | ExprKind::Struct(_)
4534            | ExprKind::Repeat(_, _)
4535            | ExprKind::Yield(_)
4536            | ExprKind::Yeet(_)
4537            | ExprKind::Become(_)
4538            | ExprKind::IncludedBytes(_)
4539            | ExprKind::FormatArgs(_)
4540            | ExprKind::Err(_)
4541            | ExprKind::DirectConstArg(_)
4542            | ExprKind::Dummy => {
4543                // These would forbid any let expressions they contain already.
4544            }
4545        }
4546        self.depth -= 1;
4547    }
4548}