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                            // Look for usages of '=>' where '>=' might be intended
2781                            if maybe_fatarrow == token::FatArrow {
2782                                err.span_suggestion_verbose(
2783                                    maybe_fatarrow.span,
2784                                    "you might have meant to write a \"greater than or equal to\" comparison",
2785                                    ">=",
2786                                    Applicability::MaybeIncorrect,
2787                                );
2788                            }
2789                            err.span_note(
2790                                cond_span,
2791                                "the `if` expression is missing a block after this condition",
2792                            );
2793                        }
2794                        err
2795                    })?
2796            };
2797            self.error_on_if_block_attrs(lo, false, block.span, attrs);
2798            block
2799        };
2800        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 };
2801        Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2802    }
2803
2804    /// Parses the condition of a `if` or `while` expression.
2805    ///
2806    /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
2807    /// i.e. the same span we use to later decide whether the drop behaviour should be that of
2808    /// edition `..=2021` or that of `2024..`.
2809    // Public to use it for custom `if` expressions in rustfmt forks like https://github.com/tucant/rustfmt
2810    pub fn parse_expr_cond(
2811        &mut self,
2812        let_chains_policy: LetChainsPolicy,
2813    ) -> PResult<'a, Box<Expr>> {
2814        let mut cond =
2815            self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET)?;
2816
2817        let mut checker = CondChecker::new(self, let_chains_policy);
2818        checker.visit_expr(&mut cond);
2819        Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2820            self.mk_expr_err(cond.span, guar)
2821        } else {
2822            cond
2823        })
2824    }
2825
2826    /// Parses a `let $pat = $expr` pseudo-expression.
2827    fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
2828        let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2829            let err = diagnostics::ExpectedExpressionFoundLet {
2830                span: self.token.span,
2831                reason: diagnostics::ForbiddenLetReason::OtherForbidden,
2832                missing_let: None,
2833                comparison: None,
2834            };
2835            if self.prev_token == token::Or {
2836                // This was part of a closure, the that part of the parser recover.
2837                return Err(self.dcx().create_err(err));
2838            } else {
2839                Recovered::Yes(self.dcx().emit_err(err))
2840            }
2841        } else {
2842            Recovered::No
2843        };
2844        self.bump(); // Eat `let` token
2845        let lo = self.prev_token.span;
2846        let pat = self.parse_pat_no_top_guard(
2847            None,
2848            RecoverComma::Yes,
2849            RecoverColon::Yes,
2850            CommaRecoveryMode::LikelyTuple,
2851        )?;
2852        if self.token == token::EqEq {
2853            self.dcx().emit_err(diagnostics::ExpectedEqForLetExpr {
2854                span: self.token.span,
2855                sugg_span: self.token.span,
2856            });
2857            self.bump();
2858        } else {
2859            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq))?;
2860        }
2861        let expr = self.parse_expr_assoc(Bound::Excluded(prec_let_scrutinee_needs_par()))?;
2862        let span = lo.to(expr.span);
2863        Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered)))
2864    }
2865
2866    /// Parses an `else { ... }` expression (`else` token already eaten).
2867    fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> {
2868        let else_span = self.prev_token.span; // `else`
2869        let attrs = self.parse_outer_attributes()?; // For recovery.
2870        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)) {
2871            self.parse_expr_if()?
2872        } else if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2873            self.parse_simple_block()?
2874        } else {
2875            let snapshot = self.create_snapshot_for_diagnostic();
2876            let first_tok = super::token_descr(&self.token);
2877            let first_tok_span = self.token.span;
2878            match self.parse_expr() {
2879                Ok(cond)
2880                // Try to guess the difference between a "condition-like" vs
2881                // "statement-like" expression.
2882                //
2883                // We are seeing the following code, in which $cond is neither
2884                // ExprKind::Block nor ExprKind::If (the 2 cases wherein this
2885                // would be valid syntax).
2886                //
2887                //     if ... {
2888                //     } else $cond
2889                //
2890                // If $cond is "condition-like" such as ExprKind::Binary, we
2891                // want to suggest inserting `if`.
2892                //
2893                //     if ... {
2894                //     } else if a == b {
2895                //            ^^
2896                //     }
2897                //
2898                // We account for macro calls that were meant as conditions as well.
2899                //
2900                //     if ... {
2901                //     } else if macro! { foo bar } {
2902                //            ^^
2903                //     }
2904                //
2905                // If $cond is "statement-like" such as ExprKind::While then we
2906                // want to suggest wrapping in braces.
2907                //
2908                //     if ... {
2909                //     } else {
2910                //            ^
2911                //         while true {}
2912                //     }
2913                //     ^
2914                    if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBrace,
    token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
2915                        && (classify::expr_requires_semi_to_be_stmt(&cond)
2916                            || #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
    ExprKind::MacCall(..) => true,
    _ => false,
}matches!(cond.kind, ExprKind::MacCall(..)))
2917                    =>
2918                {
2919                    self.dcx().emit_err(diagnostics::ExpectedElseBlock {
2920                        first_tok_span,
2921                        first_tok,
2922                        else_span,
2923                        condition_start: cond.span.shrink_to_lo(),
2924                    });
2925                    self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2926                }
2927                Err(e) => {
2928                    e.cancel();
2929                    self.restore_snapshot(snapshot);
2930                    self.parse_simple_block()?
2931                },
2932                Ok(_) => {
2933                    self.restore_snapshot(snapshot);
2934                    self.parse_simple_block()?
2935                },
2936            }
2937        };
2938        self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2939        Ok(expr)
2940    }
2941
2942    fn error_on_if_block_attrs(
2943        &self,
2944        ctx_span: Span,
2945        is_ctx_else: bool,
2946        branch_span: Span,
2947        attrs: AttrWrapper,
2948    ) {
2949        if !attrs.is_empty()
2950            && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2951        {
2952            let attributes = x0.span.until(branch_span);
2953            let last = xn.span;
2954            let ctx = if is_ctx_else { "else" } else { "if" };
2955            self.dcx().emit_err(diagnostics::OuterAttributeNotAllowedOnIfElse {
2956                last,
2957                branch_span,
2958                ctx_span,
2959                ctx: ctx.to_string(),
2960                attributes,
2961            });
2962        }
2963    }
2964
2965    fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> {
2966        if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2967            && let BinOpKind::And = binop
2968            && let ExprKind::If(cond, ..) = &right.kind
2969        {
2970            Err(self.dcx().create_err(diagnostics::UnexpectedIfWithIf(
2971                binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2972            )))
2973        } else {
2974            Ok(())
2975        }
2976    }
2977
2978    // Public to use it for custom `for` expressions in rustfmt forks like https://github.com/tucant/rustfmt
2979    pub fn parse_for_head(&mut self) -> PResult<'a, (Pat, Box<Expr>)> {
2980        let begin_paren = if self.token == token::OpenParen {
2981            // Record whether we are about to parse `for (`.
2982            // This is used below for recovery in case of `for ( $stuff ) $block`
2983            // in which case we will suggest `for $stuff $block`.
2984            let start_span = self.token.span;
2985            let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2986            Some((start_span, left))
2987        } else {
2988            None
2989        };
2990        // Try to parse the pattern `for ($PAT) in $EXPR`.
2991        let pat = match (
2992            self.parse_pat_allow_top_guard(
2993                None,
2994                RecoverComma::Yes,
2995                RecoverColon::Yes,
2996                CommaRecoveryMode::LikelyTuple,
2997            ),
2998            begin_paren,
2999        ) {
3000            (Ok(pat), _) => pat, // Happy path.
3001            (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)) => {
3002                // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
3003                // happen right before the return of this method.
3004                let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL) {
3005                    Ok(expr) => expr,
3006                    Err(expr_err) => {
3007                        // We don't know what followed the `in`, so cancel and bubble up the
3008                        // original error.
3009                        expr_err.cancel();
3010                        return Err(err);
3011                    }
3012                };
3013                return if self.token == token::CloseParen {
3014                    // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
3015                    // parser state and emit a targeted suggestion.
3016                    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];
3017                    let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
3018                    self.bump(); // )
3019                    err.cancel();
3020                    self.dcx().emit_err(diagnostics::ParenthesesInForHead {
3021                        span,
3022                        // With e.g. `for (x) in y)` this would replace `(x) in y)`
3023                        // with `x) in y)` which is syntactically invalid.
3024                        // However, this is prevented before we get here.
3025                        sugg: diagnostics::ParenthesesInForHeadSugg { left, right },
3026                    });
3027                    Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
3028                } else {
3029                    Err(err) // Some other error, bubble up.
3030                };
3031            }
3032            (Err(err), _) => return Err(err), // Some other error, bubble up.
3033        };
3034        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)) {
3035            self.error_missing_in_for_loop();
3036        }
3037        self.check_for_for_in_in_typo(self.prev_token.span);
3038        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3039        Ok((pat, expr))
3040    }
3041
3042    /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
3043    fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3044        let is_await =
3045            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));
3046
3047        if is_await {
3048            self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
3049        }
3050
3051        let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
3052
3053        let (pat, expr) = self.parse_for_head()?;
3054        let pat = Box::new(pat);
3055        // Recover from missing expression in `for` loop
3056        if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    ExprKind::Block(..) => true,
    _ => false,
}matches!(expr.kind, ExprKind::Block(..))
3057            && self.token.kind != token::OpenBrace
3058            && self.may_recover()
3059        {
3060            let guar = self.dcx().emit_err(diagnostics::MissingExpressionInForLoop {
3061                span: expr.span.shrink_to_lo(),
3062            });
3063            let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
3064            let block = self.mk_block(::thin_vec::ThinVec::new()thin_vec![], BlockCheckMode::Default, self.prev_token.span);
3065            return Ok(self.mk_expr(
3066                lo.to(self.prev_token.span),
3067                ExprKind::ForLoop(Box::new(ForLoop {
3068                    pat,
3069                    iter: err_expr,
3070                    body: block,
3071                    label: opt_label,
3072                    kind,
3073                })),
3074            ));
3075        }
3076
3077        let (attrs, loop_block) = self.parse_inner_attrs_and_block(
3078            // Only suggest moving erroneous block label to the loop header
3079            // if there is not already a label there
3080            opt_label.is_none().then_some(lo),
3081        )?;
3082
3083        let kind = ExprKind::ForLoop(Box::new(ForLoop {
3084            pat,
3085            iter: expr,
3086            body: loop_block,
3087            label: opt_label,
3088            kind,
3089        }));
3090
3091        self.recover_loop_else("for", lo)?;
3092
3093        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3094    }
3095
3096    /// Recovers from an `else` clause after a loop (`for...else`, `while...else`)
3097    fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
3098        if self.token.is_keyword(kw::Else) && self.may_recover() {
3099            let else_span = self.token.span;
3100            self.bump();
3101            let else_clause = self.parse_expr_else()?;
3102            self.dcx().emit_err(diagnostics::LoopElseNotSupported {
3103                span: else_span.to(else_clause.span),
3104                loop_kind,
3105                loop_kw,
3106            });
3107        }
3108        Ok(())
3109    }
3110
3111    fn error_missing_in_for_loop(&mut self) {
3112        let (span, sub) = if self.token.is_ident_named(sym::of) {
3113            // Possibly using JS syntax (#75311).
3114            let span = self.token.span;
3115            self.bump();
3116            (span, Some(diagnostics::MissingInInForLoopSub::InNotOf(span)))
3117        } else if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
3118            let span = self.prev_token.span;
3119            (span, Some(diagnostics::MissingInInForLoopSub::InNotEq(span)))
3120        } else {
3121            let span = self.prev_token.span.between(self.token.span);
3122            let sub = (!self.for_loop_head_has_in())
3123                .then_some(diagnostics::MissingInInForLoopSub::AddIn(span));
3124            (span, sub)
3125        };
3126
3127        self.dcx().emit_err(diagnostics::MissingInInForLoop { span, sub });
3128    }
3129
3130    /// Whether the `for` loop header already contains an `in` before its body.
3131    /// If it does, the binding is malformed (e.g. `for i i in 0..10`) rather
3132    /// than missing `in`, so suggesting another `in` would just be invalid too.
3133    fn for_loop_head_has_in(&self) -> bool {
3134        let mut dist = 0;
3135        loop {
3136            let (is_in, is_end) = self.look_ahead(dist, |t| {
3137                (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))
3138            });
3139            if is_in {
3140                return true;
3141            }
3142            if is_end {
3143                return false;
3144            }
3145            dist += 1;
3146        }
3147    }
3148
3149    /// Parses a `while` or `while let` expression (`while` token already eaten).
3150    fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3151        let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3152        let cond = self.parse_expr_cond(policy).map_err(|mut err| {
3153            err.span_label(lo, "while parsing the condition of this `while` expression");
3154            err
3155        })?;
3156        let (attrs, body) = self
3157            .parse_inner_attrs_and_block(
3158                // Only suggest moving erroneous block label to the loop header
3159                // if there is not already a label there
3160                opt_label.is_none().then_some(lo),
3161            )
3162            .map_err(|mut err| {
3163                err.span_label(lo, "while parsing the body of this `while` expression");
3164                err.span_label(cond.span, "this `while` condition successfully parsed");
3165                err
3166            })?;
3167
3168        self.recover_loop_else("while", lo)?;
3169
3170        Ok(self.mk_expr_with_attrs(
3171            lo.to(self.prev_token.span),
3172            ExprKind::While(cond, body, opt_label),
3173            attrs,
3174        ))
3175    }
3176
3177    /// Parses `loop { ... }` (`loop` token already eaten).
3178    fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3179        let loop_span = self.prev_token.span;
3180        let (attrs, body) = self.parse_inner_attrs_and_block(
3181            // Only suggest moving erroneous block label to the loop header
3182            // if there is not already a label there
3183            opt_label.is_none().then_some(lo),
3184        )?;
3185        self.recover_loop_else("loop", lo)?;
3186        Ok(self.mk_expr_with_attrs(
3187            lo.to(self.prev_token.span),
3188            ExprKind::Loop(body, opt_label, loop_span),
3189            attrs,
3190        ))
3191    }
3192
3193    pub(crate) fn eat_label(&mut self) -> Option<Label> {
3194        if let Some((ident, is_raw)) = self.token.lifetime() {
3195            // Disallow `'fn`, but with a better error message than `expect_lifetime`.
3196            if is_raw == IdentIsRaw::No && ident.without_first_quote().is_reserved() {
3197                self.dcx().emit_err(diagnostics::KeywordLabel { span: ident.span });
3198            }
3199
3200            self.bump();
3201            Some(Label { ident })
3202        } else {
3203            None
3204        }
3205    }
3206
3207    /// Parses a `match ... { ... }` expression (`match` token already eaten).
3208    fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> {
3209        let match_span = self.prev_token.span;
3210        let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3211
3212        self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
3213    }
3214
3215    /// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
3216    /// expression. This is after the match token and scrutinee are eaten
3217    fn parse_match_block(
3218        &mut self,
3219        lo: Span,
3220        match_span: Span,
3221        scrutinee: Box<Expr>,
3222        match_kind: MatchKind,
3223    ) -> PResult<'a, Box<Expr>> {
3224        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)) {
3225            if self.token == token::Semi {
3226                e.span_suggestion_short(
3227                    match_span,
3228                    "try removing this `match`",
3229                    "",
3230                    Applicability::MaybeIncorrect, // speculative
3231                );
3232            }
3233            if self.maybe_recover_unexpected_block_label(None) {
3234                e.cancel();
3235                self.bump();
3236            } else {
3237                return Err(e);
3238            }
3239        }
3240        let attrs = self.parse_inner_attributes()?;
3241
3242        let mut arms = ThinVec::new();
3243        while self.token != token::CloseBrace {
3244            match self.parse_arm() {
3245                Ok(arm) => arms.push(arm),
3246                Err(e) => {
3247                    // Recover by skipping to the end of the block.
3248                    let guar = e.emit();
3249                    self.recover_stmt();
3250                    let span = lo.to(self.token.span);
3251                    if self.token == token::CloseBrace {
3252                        self.bump();
3253                    }
3254                    // Always push at least one arm to make the match non-empty
3255                    arms.push(Arm {
3256                        attrs: Default::default(),
3257                        pat: Box::new(self.mk_pat(span, ast::PatKind::Err(guar))),
3258                        guard: None,
3259                        body: Some(self.mk_expr_err(span, guar)),
3260                        span,
3261                        id: DUMMY_NODE_ID,
3262                        is_placeholder: false,
3263                    });
3264                    return Ok(self.mk_expr_with_attrs(
3265                        span,
3266                        ExprKind::Match(scrutinee, arms, match_kind),
3267                        attrs,
3268                    ));
3269                }
3270            }
3271        }
3272        let hi = self.token.span;
3273        self.bump();
3274        Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
3275    }
3276
3277    /// Attempt to recover from match arm body with statements and no surrounding braces.
3278    fn parse_arm_body_missing_braces(
3279        &mut self,
3280        first_expr: &Box<Expr>,
3281        arrow_span: Span,
3282    ) -> Option<(Span, ErrorGuaranteed)> {
3283        if self.token != token::Semi {
3284            return None;
3285        }
3286        let start_snapshot = self.create_snapshot_for_diagnostic();
3287        let semi_sp = self.token.span;
3288        self.bump(); // `;`
3289        let mut stmts =
3290            ::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()))];
3291        let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3292            let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3293
3294            let guar = this.dcx().emit_err(diagnostics::MatchArmBodyWithoutBraces {
3295                statements: span,
3296                arrow: arrow_span,
3297                num_statements: stmts.len(),
3298                sub: if stmts.len() > 1 {
3299                    diagnostics::MatchArmBodyWithoutBracesSugg::AddBraces {
3300                        left: span.shrink_to_lo(),
3301                        right: span.shrink_to_hi(),
3302                        num_statements: stmts.len(),
3303                    }
3304                } else {
3305                    diagnostics::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
3306                },
3307            });
3308            (span, guar)
3309        };
3310        // We might have either a `,` -> `;` typo, or a block without braces. We need
3311        // a more subtle parsing strategy.
3312        loop {
3313            if self.token == token::CloseBrace {
3314                // We have reached the closing brace of the `match` expression.
3315                return Some(err(self, stmts));
3316            }
3317            if self.token == token::Comma {
3318                self.restore_snapshot(start_snapshot);
3319                return None;
3320            }
3321            let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3322            match self.parse_pat_no_top_alt(None, None) {
3323                Ok(_pat) => {
3324                    if self.token == token::FatArrow {
3325                        // Reached arm end.
3326                        self.restore_snapshot(pre_pat_snapshot);
3327                        return Some(err(self, stmts));
3328                    }
3329                }
3330                Err(err) => {
3331                    err.cancel();
3332                }
3333            }
3334
3335            self.restore_snapshot(pre_pat_snapshot);
3336            match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3337                // Consume statements for as long as possible.
3338                Ok(stmt) => {
3339                    stmts.push(stmt);
3340                }
3341                // We couldn't parse either yet another statement missing it's
3342                // enclosing block nor the next arm's pattern or closing brace.
3343                Err(stmt_err) => {
3344                    stmt_err.cancel();
3345                    self.restore_snapshot(start_snapshot);
3346                    break;
3347                }
3348            }
3349        }
3350        None
3351    }
3352
3353    pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3354        let attrs = self.parse_outer_attributes()?;
3355        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3356            let lo = this.token.span;
3357            let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3358            let pat = Box::new(pat);
3359
3360            let span_before_body = this.prev_token.span;
3361            let arm_body;
3362            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));
3363            let is_almost_fat_arrow =
3364                TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3365
3366            // this avoids the compiler saying that a `,` or `}` was expected even though
3367            // the pattern isn't a never pattern (and thus an arm body is required)
3368            let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3369                || #[allow(non_exhaustive_omitted_patterns)] match this.token.kind {
    token::Comma | token::CloseBrace => true,
    _ => false,
}matches!(this.token.kind, token::Comma | token::CloseBrace);
3370
3371            let mut result = if armless {
3372                // A pattern without a body, allowed for never patterns.
3373                arm_body = None;
3374                let span = lo.to(this.prev_token.span);
3375                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| {
3376                    // Don't gate twice
3377                    if !pat.contains_never_pattern() {
3378                        this.psess.gated_spans.gate(sym::never_patterns, span);
3379                    }
3380                    x
3381                })
3382            } else {
3383                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)) {
3384                    // We might have a `=>` -> `=` or `->` typo (issue #89396).
3385                    if is_almost_fat_arrow {
3386                        err.span_suggestion_verbose(
3387                            this.token.span,
3388                            "use a fat arrow to start a match arm",
3389                            "=>",
3390                            Applicability::MachineApplicable,
3391                        );
3392                        if #[allow(non_exhaustive_omitted_patterns)] match (&this.prev_token.kind,
        &this.token.kind) {
    (token::DotDotEq, token::Gt) => true,
    _ => false,
}matches!(
3393                            (&this.prev_token.kind, &this.token.kind),
3394                            (token::DotDotEq, token::Gt)
3395                        ) {
3396                            // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
3397                            // so we suppress the error here
3398                            err.delay_as_bug();
3399                        } else {
3400                            err.emit();
3401                        }
3402                        this.bump();
3403                    } else {
3404                        return Err(err);
3405                    }
3406                }
3407                let arrow_span = this.prev_token.span;
3408                let arm_start_span = this.token.span;
3409
3410                let expr =
3411                    this.parse_expr_res(Restrictions::STMT_EXPR).map_err(|mut err| {
3412                        err.span_label(arrow_span, "while parsing the `match` arm starting here");
3413                        err
3414                    })?;
3415
3416                let require_comma =
3417                    !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3418
3419                if !require_comma {
3420                    arm_body = Some(expr);
3421                    // Eat a comma if it exists, though.
3422                    let _ = this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3423                    Ok(Recovered::No)
3424                } else if let Some((span, guar)) =
3425                    this.parse_arm_body_missing_braces(&expr, arrow_span)
3426                {
3427                    let body = this.mk_expr_err(span, guar);
3428                    arm_body = Some(body);
3429                    Ok(Recovered::Yes(guar))
3430                } else {
3431                    let expr_span = expr.span;
3432                    arm_body = Some(expr);
3433                    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| {
3434                        if this.token == token::FatArrow {
3435                            let sm = this.psess.source_map();
3436                            if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3437                                && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3438                                && expr_lines.lines.len() == 2
3439                            {
3440                                if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3441                                    // We check whether there's any trailing code in the parse span,
3442                                    // if there isn't, we very likely have the following:
3443                                    //
3444                                    // X |     &Y => "y"
3445                                    //   |        --    - missing comma
3446                                    //   |        |
3447                                    //   |        arrow_span
3448                                    // X |     &X => "x"
3449                                    //   |      - ^^ self.token.span
3450                                    //   |      |
3451                                    //   |      parsed until here as `"y" & X`
3452                                    err.span_suggestion_short(
3453                                        arm_start_span.shrink_to_hi(),
3454                                        "missing a comma here to end this `match` arm",
3455                                        ",",
3456                                        Applicability::MachineApplicable,
3457                                    );
3458                                } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3459                                    == expr_lines.lines[0].end_col
3460                                {
3461                                    // similar to the above, but we may typo a `.` or `/` at the end of the line
3462                                    let comma_span = arm_start_span
3463                                        .shrink_to_hi()
3464                                        .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3465                                    if let Ok(res) = sm.span_to_snippet(comma_span)
3466                                        && (res == "." || res == "/")
3467                                    {
3468                                        err.span_suggestion_short(
3469                                            comma_span,
3470                                            "you might have meant to write a `,` to end this `match` arm",
3471                                            ",",
3472                                            Applicability::MachineApplicable,
3473                                        );
3474                                    }
3475                                }
3476                            }
3477                        } else {
3478                            err.span_label(
3479                                arrow_span,
3480                                "while parsing the `match` arm starting here",
3481                            );
3482                        }
3483                        err
3484                    })
3485                }
3486            };
3487
3488            let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3489            let arm_span = lo.to(hi_span);
3490
3491            // We want to recover:
3492            // X |     Some(_) => foo()
3493            //   |                     - missing comma
3494            // X |     None => "x"
3495            //   |     ^^^^ self.token.span
3496            // as well as:
3497            // X |     Some(!)
3498            //   |            - missing comma
3499            // X |     None => "x"
3500            //   |     ^^^^ self.token.span
3501            // But we musn't recover
3502            // X |     pat[0] => {}
3503            //   |        ^ self.token.span
3504            let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3505            if recover_missing_comma {
3506                result = result.or_else(|err| {
3507                    // FIXME(compiler-errors): We could also recover `; PAT =>` here
3508
3509                    // Try to parse a following `PAT =>`, if successful
3510                    // then we should recover.
3511                    let mut snapshot = this.create_snapshot_for_diagnostic();
3512                    let pattern_follows = snapshot
3513                        .parse_pat_no_top_guard(
3514                            None,
3515                            RecoverComma::Yes,
3516                            RecoverColon::Yes,
3517                            CommaRecoveryMode::EitherTupleOrPipe,
3518                        )
3519                        .map_err(|err| err.cancel())
3520                        .is_ok();
3521                    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)) {
3522                        err.cancel();
3523                        let guar = this.dcx().emit_err(diagnostics::MissingCommaAfterMatchArm {
3524                            span: arm_span.shrink_to_hi(),
3525                        });
3526                        return Ok(Recovered::Yes(guar));
3527                    }
3528                    Err(err)
3529                });
3530            }
3531            result?;
3532
3533            Ok((
3534                ast::Arm {
3535                    attrs,
3536                    pat,
3537                    guard,
3538                    body: arm_body,
3539                    span: arm_span,
3540                    id: DUMMY_NODE_ID,
3541                    is_placeholder: false,
3542                },
3543                Trailing::No,
3544                UsePreAttrPos::No,
3545            ))
3546        })
3547    }
3548
3549    pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
3550        self.eat_metavar_seq(MetaVarKind::Guard, |this| {
3551            this.expect_match_arm_guard(ForceCollect::Yes)
3552        })
3553    }
3554
3555    fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
3556        if let Some(guard) = self.eat_metavar_guard() {
3557            return Ok(Some(guard));
3558        }
3559
3560        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)) {
3561            // No match arm guard present.
3562            return Ok(None);
3563        }
3564        self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
3565    }
3566
3567    pub(crate) fn expect_match_arm_guard(
3568        &mut self,
3569        force_collect: ForceCollect,
3570    ) -> PResult<'a, Box<Guard>> {
3571        if let Some(guard) = self.eat_metavar_guard() {
3572            return Ok(guard);
3573        }
3574
3575        self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::If,
    token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If))?;
3576        self.expect_match_arm_guard_cond(force_collect)
3577    }
3578
3579    fn expect_match_arm_guard_cond(
3580        &mut self,
3581        force_collect: ForceCollect,
3582    ) -> PResult<'a, Box<Guard>> {
3583        let leading_if_span = self.prev_token.span;
3584
3585        let mut cond = self.parse_match_guard_condition(force_collect)?;
3586        let cond_span = cond.span;
3587
3588        CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3589
3590        let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
3591        Ok(Box::new(guard))
3592    }
3593
3594    fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
3595        if self.token == token::OpenParen {
3596            let left = self.token.span;
3597            let pat = self.parse_pat_no_top_guard(
3598                None,
3599                RecoverComma::Yes,
3600                RecoverColon::Yes,
3601                CommaRecoveryMode::EitherTupleOrPipe,
3602            )?;
3603            if let ast::PatKind::Paren(subpat) = &pat.kind
3604                && let ast::PatKind::Guard(..) = &subpat.kind
3605            {
3606                // Detect and recover from `($pat if $cond) => $arm`.
3607                // FIXME(guard_patterns): convert this to a normal guard instead
3608                let span = pat.span;
3609                let ast::PatKind::Paren(subpat) = pat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3610                let ast::PatKind::Guard(_, mut guard) = subpat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3611                self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
3612                let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3613                checker.visit_expr(&mut guard.cond);
3614
3615                let right = self.prev_token.span;
3616                self.dcx().emit_err(diagnostics::ParenthesesInMatchPat {
3617                    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],
3618                    sugg: diagnostics::ParenthesesInMatchPatSugg { left, right },
3619                });
3620
3621                if let Some(guar) = checker.found_incorrect_let_chain {
3622                    guard.cond = *self.mk_expr_err(guard.span(), guar);
3623                }
3624                Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
3625            } else {
3626                Ok((pat, self.parse_match_arm_guard()?))
3627            }
3628        } else {
3629            // Regular parser flow:
3630            let pat = self.parse_pat_no_top_guard(
3631                None,
3632                RecoverComma::Yes,
3633                RecoverColon::Yes,
3634                CommaRecoveryMode::EitherTupleOrPipe,
3635            )?;
3636            Ok((pat, self.parse_match_arm_guard()?))
3637        }
3638    }
3639
3640    fn parse_match_guard_condition(
3641        &mut self,
3642        force_collect: ForceCollect,
3643    ) -> PResult<'a, Box<Expr>> {
3644        let attrs = self.parse_outer_attributes()?;
3645        let expr = self.collect_tokens(
3646            None,
3647            AttrWrapper::empty(),
3648            force_collect,
3649            |this, _empty_attrs| {
3650                match this.parse_expr_res_after_attrs(
3651                    Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD,
3652                    attrs,
3653                ) {
3654                    Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
3655                    Err(mut err) => {
3656                        if this.prev_token == token::OpenBrace {
3657                            let sugg_sp = this.prev_token.span.shrink_to_lo();
3658                            // Consume everything within the braces, let's avoid further parse
3659                            // errors.
3660                            this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3661                            let msg =
3662                                "you might have meant to start a match arm after the match guard";
3663                            if this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
3664                                let applicability = if this.token != token::FatArrow {
3665                                    // We have high confidence that we indeed didn't have a struct
3666                                    // literal in the match guard, but rather we had some operation
3667                                    // that ended in a path, immediately followed by a block that was
3668                                    // meant to be the match arm.
3669                                    Applicability::MachineApplicable
3670                                } else {
3671                                    Applicability::MaybeIncorrect
3672                                };
3673                                err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3674                            }
3675                        }
3676                        Err(err)
3677                    }
3678                }
3679            },
3680        )?;
3681        Ok(expr)
3682    }
3683
3684    pub(crate) fn is_builtin(&self) -> bool {
3685        self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
3686    }
3687
3688    /// Parses a `try {...}` or `try bikeshed Ty {...}` expression (`try` token already eaten).
3689    fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> {
3690        let annotation =
3691            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 };
3692
3693        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3694        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)) {
3695            Err(self.dcx().create_err(diagnostics::CatchAfterTry { span: self.prev_token.span }))
3696        } else {
3697            let span = span_lo.to(body.span);
3698            let gate_sym =
3699                if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous };
3700            self.psess.gated_spans.gate(gate_sym, span);
3701            Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs))
3702        }
3703    }
3704
3705    fn is_do_catch_block(&self) -> bool {
3706        self.token.is_keyword(kw::Do)
3707            && self.is_keyword_ahead(1, &[kw::Catch])
3708            && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3709            && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3710    }
3711
3712    fn is_do_yeet(&self) -> bool {
3713        self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3714    }
3715
3716    fn is_try_block(&self) -> bool {
3717        self.token.is_keyword(kw::Try)
3718            && self.look_ahead(1, |t| {
3719                *t == token::OpenBrace
3720                    || t.is_metavar_block()
3721                    || t.kind == TokenKind::Ident(sym::bikeshed, IdentIsRaw::No)
3722            })
3723            && self.token_uninterpolated_span().at_least_rust_2018()
3724    }
3725
3726    /// Parses an `async move? {...}` or `gen move? {...}` expression.
3727    fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> {
3728        let lo = self.token.span;
3729        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)) {
3730            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 }
3731        } else {
3732            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)));
3733            GenBlockKind::Gen
3734        };
3735        match kind {
3736            GenBlockKind::Async => {
3737                // `async` blocks are stable
3738            }
3739            GenBlockKind::Gen | GenBlockKind::AsyncGen => {
3740                self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3741            }
3742        }
3743        let capture_clause = self.parse_capture_clause()?;
3744        let decl_span = lo.to(self.prev_token.span);
3745        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3746        let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3747        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3748    }
3749
3750    fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3751        self.is_keyword_ahead(lookahead, &[kw])
3752            && ((
3753                // `async move {`
3754                self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3755                    && self.look_ahead(lookahead + 2, |t| {
3756                        *t == token::OpenBrace || t.is_metavar_block()
3757                    })
3758            ) || (
3759                // `async {`
3760                self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3761            ))
3762    }
3763
3764    pub(super) fn is_async_gen_block(&self) -> bool {
3765        self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3766    }
3767
3768    fn is_likely_struct_lit(&self) -> bool {
3769        // `{ ident, ` and `{ ident: ` cannot start a block.
3770        self.look_ahead(1, |t| t.is_ident())
3771            && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3772    }
3773
3774    fn maybe_parse_struct_expr(
3775        &mut self,
3776        qself: &Option<Box<ast::QSelf>>,
3777        path: &ast::Path,
3778    ) -> Option<PResult<'a, Box<Expr>>> {
3779        let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3780        match (struct_allowed, self.is_likely_struct_lit()) {
3781            // A struct literal isn't expected and one is pretty much assured not to be present. The
3782            // only situation that isn't detected is when a struct with a single field was attempted
3783            // in a place where a struct literal wasn't expected, but regular parser errors apply.
3784            // Happy path.
3785            (false, false) => None,
3786            (true, _) => {
3787                // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for
3788                // any kind of recovery. Happy path.
3789                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)) {
3790                    return Some(Err(err));
3791                }
3792                Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
3793            }
3794            (false, true) => {
3795                // We have something like `match foo { bar,` or `match foo { bar:`, which means the
3796                // user might have meant to write a struct literal as part of the `match`
3797                // discriminant. This is done purely for error recovery.
3798                let snapshot = self.create_snapshot_for_diagnostic();
3799                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)) {
3800                    return Some(Err(err));
3801                }
3802                match self.parse_expr_struct(qself.clone(), path.clone(), false) {
3803                    Ok(expr) => {
3804                        // This is a struct literal, but we don't accept them here.
3805                        self.dcx().emit_err(diagnostics::StructLiteralNotAllowedHere {
3806                            span: expr.span,
3807                            sub: diagnostics::StructLiteralNotAllowedHereSugg {
3808                                left: path.span.shrink_to_lo(),
3809                                right: expr.span.shrink_to_hi(),
3810                            },
3811                        });
3812                        Some(Ok(expr))
3813                    }
3814                    Err(err) => {
3815                        // We couldn't parse a valid struct, rollback and let the parser emit an
3816                        // error elsewhere.
3817                        err.cancel();
3818                        self.restore_snapshot(snapshot);
3819                        None
3820                    }
3821                }
3822            }
3823        }
3824    }
3825
3826    fn maybe_recover_bad_struct_literal_path(
3827        &mut self,
3828        is_underscore_entry_point: bool,
3829    ) -> PResult<'a, Option<Box<Expr>>> {
3830        if self.may_recover()
3831            && self.check_noexpect(&token::OpenBrace)
3832            && (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3833                && self.is_likely_struct_lit())
3834        {
3835            let span = if is_underscore_entry_point {
3836                self.prev_token.span
3837            } else {
3838                self.token.span.shrink_to_lo()
3839            };
3840
3841            self.bump(); // {
3842            let expr = self.parse_expr_struct(
3843                None,
3844                Path::from_ident(Ident::new(kw::Underscore, span)),
3845                false,
3846            )?;
3847
3848            let guar = if is_underscore_entry_point {
3849                self.dcx().create_err(diagnostics::StructLiteralPlaceholderPath { span }).emit()
3850            } else {
3851                self.dcx()
3852                    .create_err(diagnostics::StructLiteralWithoutPathLate {
3853                        span: expr.span,
3854                        suggestion_span: expr.span.shrink_to_lo(),
3855                    })
3856                    .emit()
3857            };
3858
3859            Ok(Some(self.mk_expr_err(expr.span, guar)))
3860        } else {
3861            Ok(None)
3862        }
3863    }
3864
3865    pub(super) fn parse_struct_fields(
3866        &mut self,
3867        pth: ast::Path,
3868        recover: bool,
3869        close: ExpTokenPair,
3870    ) -> PResult<
3871        'a,
3872        (
3873            ThinVec<ExprField>,
3874            ast::StructRest,
3875            Option<ErrorGuaranteed>, /* async blocks are forbidden in Rust 2015 */
3876        ),
3877    > {
3878        let mut fields = ThinVec::new();
3879        let mut base = ast::StructRest::None;
3880        let mut recovered_async = None;
3881        let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3882
3883        let async_block_err = |e: &mut Diag<'_>, span: Span| {
3884            diagnostics::AsyncBlockIn2015 { span }.add_to_diag(e);
3885            diagnostics::HelpUseLatestEdition::new().add_to_diag(e);
3886        };
3887
3888        while self.token != close.tok {
3889            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) {
3890                let exp_span = self.prev_token.span;
3891                // We permit `.. }` on the left-hand side of a destructuring assignment.
3892                if self.check(close) {
3893                    base = ast::StructRest::Rest(self.prev_token.span);
3894                    break;
3895                }
3896                match self.parse_expr() {
3897                    Ok(e) => base = ast::StructRest::Base(e),
3898                    Err(e) if recover => {
3899                        e.emit();
3900                        self.recover_stmt();
3901                    }
3902                    Err(e) => return Err(e),
3903                }
3904                self.recover_struct_comma_after_dotdot(exp_span);
3905                break;
3906            }
3907
3908            // Peek the field's ident before parsing its expr in order to emit better diagnostics.
3909            let peek = self
3910                .token
3911                .ident()
3912                .filter(|(ident, is_raw)| {
3913                    (!ident.is_reserved() || #[allow(non_exhaustive_omitted_patterns)] match is_raw {
    IdentIsRaw::Yes => true,
    _ => false,
}matches!(is_raw, IdentIsRaw::Yes))
3914                        && self.look_ahead(1, |tok| *tok == token::Colon)
3915                })
3916                .map(|(ident, _)| ident);
3917
3918            // We still want a field even if its expr didn't parse.
3919            let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3920                peek.map(|ident| {
3921                    let span = ident.span;
3922                    ExprField {
3923                        ident,
3924                        span,
3925                        expr: this.mk_expr_err(span, guar),
3926                        is_shorthand: false,
3927                        attrs: AttrVec::new(),
3928                        id: DUMMY_NODE_ID,
3929                        is_placeholder: false,
3930                    }
3931                })
3932            };
3933
3934            let parsed_field = match self.parse_expr_field() {
3935                Ok(f) => Ok(f),
3936                Err(mut e) => {
3937                    if pth == kw::Async {
3938                        async_block_err(&mut e, pth.span);
3939                    } else {
3940                        e.span_label(pth.span, "while parsing this struct");
3941                    }
3942
3943                    if let Some((ident, _)) = self.token.ident()
3944                        && !self.token.is_reserved_ident()
3945                        && self.look_ahead(1, |t| {
3946                            AssocOp::from_token(t).is_some()
3947                                || #[allow(non_exhaustive_omitted_patterns)] match t.kind {
    token::OpenParen | token::OpenBracket | token::OpenBrace => true,
    _ => false,
}matches!(
3948                                    t.kind,
3949                                    token::OpenParen | token::OpenBracket | token::OpenBrace
3950                                )
3951                                || *t == token::Dot
3952                        })
3953                    {
3954                        // Looks like they tried to write a shorthand, complex expression,
3955                        // E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
3956                        e.span_suggestion_verbose(
3957                            self.token.span.shrink_to_lo(),
3958                            "try naming a field",
3959                            &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: ",),
3960                            Applicability::MaybeIncorrect,
3961                        );
3962                    }
3963                    if in_if_guard && close.token_type == TokenType::CloseBrace {
3964                        return Err(e);
3965                    }
3966
3967                    if !recover {
3968                        return Err(e);
3969                    }
3970
3971                    let guar = e.emit();
3972                    if pth == kw::Async {
3973                        recovered_async = Some(guar);
3974                    }
3975
3976                    // If we encountered an error which we are recovering from, treat the struct
3977                    // as if it has a `..` in it, because we don’t know what fields the user
3978                    // might have *intended* it to have.
3979                    //
3980                    // This assignment will be overwritten if we actually parse a `..` later.
3981                    //
3982                    // (Note that this code is duplicated between here and below in comma parsing.
3983                    base = ast::StructRest::NoneWithError(guar);
3984
3985                    // If the next token is a comma, then try to parse
3986                    // what comes next as additional fields, rather than
3987                    // bailing out until next `}`.
3988                    if self.token != token::Comma {
3989                        self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3990                        if self.token != token::Comma {
3991                            break;
3992                        }
3993                    }
3994
3995                    Err(guar)
3996                }
3997            };
3998
3999            let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
4000            // A shorthand field can be turned into a full field with `:`.
4001            // We should point this out.
4002            self.check_or_expected(!is_shorthand, TokenType::Colon);
4003
4004            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]) {
4005                Ok(_) => {
4006                    if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
4007                    {
4008                        // Only include the field if there's no parse error for the field name.
4009                        fields.push(f);
4010                    }
4011                }
4012                Err(mut e) => {
4013                    if pth == kw::Async {
4014                        async_block_err(&mut e, pth.span);
4015                    } else {
4016                        e.span_label(pth.span, "while parsing this struct");
4017                        if peek.is_some() {
4018                            e.span_suggestion(
4019                                self.prev_token.span.shrink_to_hi(),
4020                                "try adding a comma",
4021                                ",",
4022                                Applicability::MachineApplicable,
4023                            );
4024                        }
4025                    }
4026                    if !recover {
4027                        return Err(e);
4028                    }
4029                    let guar = e.emit();
4030                    if pth == kw::Async {
4031                        recovered_async = Some(guar);
4032                    } else if let Some(f) = field_ident(self, guar) {
4033                        fields.push(f);
4034                    }
4035
4036                    // See comment above on this same assignment inside of field parsing.
4037                    base = ast::StructRest::NoneWithError(guar);
4038
4039                    self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
4040                    let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
4041                }
4042            }
4043        }
4044        Ok((fields, base, recovered_async))
4045    }
4046
4047    /// Precondition: already parsed the '{'.
4048    pub(super) fn parse_expr_struct(
4049        &mut self,
4050        qself: Option<Box<ast::QSelf>>,
4051        pth: ast::Path,
4052        recover: bool,
4053    ) -> PResult<'a, Box<Expr>> {
4054        let lo = pth.span;
4055        let (fields, base, recovered_async) =
4056            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))?;
4057        let span = lo.to(self.token.span);
4058        self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBrace,
    token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
4059        let expr = if let Some(guar) = recovered_async {
4060            ExprKind::Err(guar)
4061        } else {
4062            ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base }))
4063        };
4064        Ok(self.mk_expr(span, expr))
4065    }
4066
4067    fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
4068        if self.token != token::Comma {
4069            return;
4070        }
4071        self.dcx().emit_err(diagnostics::CommaAfterBaseStruct {
4072            span: span.to(self.prev_token.span),
4073            comma: self.token.span,
4074        });
4075        self.recover_stmt();
4076    }
4077
4078    fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
4079        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)) {
4080            // recover from typo of `...`, suggest `..`
4081            let span = self.prev_token.span;
4082            self.dcx().emit_err(diagnostics::MissingDotDot { token_span: span, sugg_span: span });
4083            return true;
4084        }
4085        false
4086    }
4087
4088    /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
4089    fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
4090        // Convert `label` -> `'label`,
4091        // so that nameres doesn't complain about non-existing label
4092        let label = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\'{0}", ident.name))
    })format!("'{}", ident.name);
4093        let ident = Ident::new(Symbol::intern(&label), ident.span);
4094
4095        self.dcx().emit_err(diagnostics::ExpectedLabelFoundIdent {
4096            span: ident.span,
4097            start: ident.span.shrink_to_lo(),
4098        });
4099
4100        Label { ident }
4101    }
4102
4103    /// Parses `ident (COLON expr)?`.
4104    fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
4105        let attrs = self.parse_outer_attributes()?;
4106        self.recover_vcs_conflict_marker();
4107        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4108            let lo = this.token.span;
4109
4110            // Check if a colon exists one ahead. This means we're parsing a fieldname.
4111            let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
4112            // Proactively check whether parsing the field will be incorrect.
4113            let is_wrong = this.token.is_non_reserved_ident()
4114                && !this.look_ahead(1, |t| {
4115                    t == &token::Colon
4116                        || t == &token::Eq
4117                        || t == &token::Comma
4118                        || t == &token::CloseBrace
4119                        || t == &token::CloseParen
4120                });
4121            if is_wrong {
4122                return Err(this.dcx().create_err(diagnostics::ExpectedStructField {
4123                    span: this.look_ahead(1, |t| t.span),
4124                    ident_span: this.token.span,
4125                    token: pprust::token_to_string(&this.look_ahead(1, |t| *t)),
4126                }));
4127            }
4128            let (ident, expr) = if is_shorthand {
4129                // Mimic `x: x` for the `x` field shorthand.
4130                let ident = this.parse_ident_common(false)?;
4131                let path = ast::Path::from_ident(ident);
4132                (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
4133            } else {
4134                let ident = this.parse_field_name()?;
4135                this.error_on_eq_field_init(ident);
4136                this.bump(); // `:`
4137                (ident, this.parse_expr()?)
4138            };
4139
4140            Ok((
4141                ast::ExprField {
4142                    ident,
4143                    span: lo.to(expr.span),
4144                    expr,
4145                    is_shorthand,
4146                    attrs,
4147                    id: DUMMY_NODE_ID,
4148                    is_placeholder: false,
4149                },
4150                Trailing::from(this.token == token::Comma),
4151                UsePreAttrPos::No,
4152            ))
4153        })
4154    }
4155
4156    /// Check for `=`. This means the source incorrectly attempts to
4157    /// initialize a field with an eq rather than a colon.
4158    fn error_on_eq_field_init(&self, field_name: Ident) {
4159        if self.token != token::Eq {
4160            return;
4161        }
4162
4163        self.dcx().emit_err(diagnostics::EqFieldInit {
4164            span: self.token.span,
4165            eq: field_name.span.shrink_to_hi().to(self.token.span),
4166        });
4167    }
4168
4169    fn err_dotdotdot_syntax(&self, span: Span) {
4170        self.dcx().emit_err(diagnostics::DotDotDot { span });
4171    }
4172
4173    fn err_larrow_operator(&self, span: Span) {
4174        self.dcx().emit_err(diagnostics::LeftArrowOperator { span });
4175    }
4176
4177    fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4178        ExprKind::AssignOp(assign_op, lhs, rhs)
4179    }
4180
4181    fn mk_range(
4182        &mut self,
4183        start: Option<Box<Expr>>,
4184        end: Option<Box<Expr>>,
4185        limits: RangeLimits,
4186    ) -> ExprKind {
4187        if end.is_none() && limits == RangeLimits::Closed {
4188            let guar = self.inclusive_range_with_incorrect_end();
4189            ExprKind::Err(guar)
4190        } else {
4191            ExprKind::Range(start, end, limits)
4192        }
4193    }
4194
4195    fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind {
4196        ExprKind::Unary(unop, expr)
4197    }
4198
4199    fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4200        ExprKind::Binary(binop, lhs, rhs)
4201    }
4202
4203    fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind {
4204        ExprKind::Index(expr, idx, brackets_span)
4205    }
4206
4207    fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind {
4208        ExprKind::Call(f, args)
4209    }
4210
4211    fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4212        let span = lo.to(self.prev_token.span);
4213        let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
4214        self.recover_from_await_method_call();
4215        await_expr
4216    }
4217
4218    fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4219        let span = lo.to(self.prev_token.span);
4220        let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
4221        self.recover_from_use();
4222        use_expr
4223    }
4224
4225    pub(crate) fn mk_expr_with_attrs(
4226        &self,
4227        span: Span,
4228        kind: ExprKind,
4229        attrs: AttrVec,
4230    ) -> Box<Expr> {
4231        Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
4232    }
4233
4234    pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> {
4235        self.mk_expr_with_attrs(span, kind, AttrVec::new())
4236    }
4237
4238    pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> {
4239        self.mk_expr(span, ExprKind::Err(guar))
4240    }
4241
4242    pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
4243        self.mk_expr(span, ExprKind::Tup(Default::default()))
4244    }
4245
4246    pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
4247        self.mk_expr(
4248            span,
4249            ast::ExprKind::Closure(Box::new(ast::Closure {
4250                binder: rustc_ast::ClosureBinder::NotPresent,
4251                constness: rustc_ast::Const::No,
4252                movability: rustc_ast::Movability::Movable,
4253                capture_clause: rustc_ast::CaptureBy::Ref,
4254                coroutine_kind: None,
4255                fn_decl: Box::new(rustc_ast::FnDecl {
4256                    inputs: Default::default(),
4257                    output: rustc_ast::FnRetTy::Default(span),
4258                }),
4259                fn_arg_span: span,
4260                fn_decl_span: span,
4261                body,
4262            })),
4263        )
4264    }
4265
4266    /// Create expression span ensuring the span of the parent node
4267    /// is larger than the span of lhs and rhs, including the attributes.
4268    fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
4269        lhs.attrs
4270            .iter()
4271            .find(|a| a.style == AttrStyle::Outer)
4272            .map_or(lhs_span, |a| a.span)
4273            .to(op_span)
4274            .to(rhs_span)
4275    }
4276
4277    fn collect_tokens_for_expr(
4278        &mut self,
4279        attrs: AttrWrapper,
4280        f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>,
4281    ) -> PResult<'a, Box<Expr>> {
4282        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4283            let res = f(this, attrs)?;
4284            let trailing = Trailing::from(
4285                this.restrictions.contains(Restrictions::STMT_EXPR)
4286                     && this.token == token::Semi
4287                // FIXME: pass an additional condition through from the place
4288                // where we know we need a comma, rather than assuming that
4289                // `#[attr] expr,` always captures a trailing comma.
4290                || this.token == token::Comma,
4291            );
4292            Ok((res, trailing, UsePreAttrPos::No))
4293        })
4294    }
4295}
4296
4297/// Could this lifetime/label be an unclosed char literal? For example, `'a`
4298/// could be, but `'abc` could not.
4299pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4300    ident.name.as_str().starts_with('\'')
4301        && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4302}
4303
4304/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
4305/// 2024 and later). In case of edition dependence, specify the currently present edition.
4306pub enum LetChainsPolicy {
4307    AlwaysAllowed,
4308    EditionDependent { current_edition: Edition },
4309}
4310
4311/// Visitor to check for invalid use of `ExprKind::Let` that can't
4312/// easily be caught in parsing. For example:
4313///
4314/// ```rust,ignore (example)
4315/// // Only know that the let isn't allowed once the `||` token is reached
4316/// if let Some(x) = y || true {}
4317/// // Only know that the let isn't allowed once the second `=` token is reached.
4318/// if let Some(x) = y && z = 1 {}
4319/// ```
4320struct CondChecker<'a> {
4321    parser: &'a Parser<'a>,
4322    let_chains_policy: LetChainsPolicy,
4323    depth: u32,
4324    forbid_let_reason: Option<diagnostics::ForbiddenLetReason>,
4325    missing_let: Option<diagnostics::MaybeMissingLet>,
4326    comparison: Option<diagnostics::MaybeComparison>,
4327    found_incorrect_let_chain: Option<ErrorGuaranteed>,
4328}
4329
4330impl<'a> CondChecker<'a> {
4331    fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4332        CondChecker {
4333            parser,
4334            forbid_let_reason: None,
4335            missing_let: None,
4336            comparison: None,
4337            let_chains_policy,
4338            found_incorrect_let_chain: None,
4339            depth: 0,
4340        }
4341    }
4342}
4343
4344impl MutVisitor for CondChecker<'_> {
4345    fn visit_expr(&mut self, e: &mut Expr) {
4346        self.depth += 1;
4347
4348        let span = e.span;
4349        match e.kind {
4350            ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4351                if let Some(reason) = self.forbid_let_reason {
4352                    let error = match reason {
4353                        diagnostics::ForbiddenLetReason::NotSupportedOr(or_span) => {
4354                            self.parser.dcx().emit_err(diagnostics::OrInLetChain { span: or_span })
4355                        }
4356                        _ => {
4357                            let guar = self.parser.dcx().emit_err(
4358                                diagnostics::ExpectedExpressionFoundLet {
4359                                    span,
4360                                    reason,
4361                                    missing_let: self.missing_let,
4362                                    comparison: self.comparison,
4363                                },
4364                            );
4365                            if let Some(_) = self.missing_let {
4366                                self.found_incorrect_let_chain = Some(guar);
4367                            }
4368                            guar
4369                        }
4370                    };
4371                    *recovered = Recovered::Yes(error);
4372                } else if self.depth > 1 {
4373                    // Top level `let` is always allowed; only gate chains
4374                    match self.let_chains_policy {
4375                        LetChainsPolicy::AlwaysAllowed => (),
4376                        LetChainsPolicy::EditionDependent { current_edition } => {
4377                            if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4378                                self.parser.dcx().emit_err(diagnostics::LetChainPre2024 { span });
4379                            }
4380                        }
4381                    }
4382                }
4383            }
4384            ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4385                mut_visit::walk_expr(self, e);
4386            }
4387            ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4388                if let None | Some(diagnostics::ForbiddenLetReason::NotSupportedOr(_)) =
4389                    self.forbid_let_reason =>
4390            {
4391                let forbid_let_reason = self.forbid_let_reason;
4392                self.forbid_let_reason =
4393                    Some(diagnostics::ForbiddenLetReason::NotSupportedOr(or_span));
4394                mut_visit::walk_expr(self, e);
4395                self.forbid_let_reason = forbid_let_reason;
4396            }
4397            ExprKind::Paren(ref inner)
4398                if let None | Some(diagnostics::ForbiddenLetReason::NotSupportedParentheses(_)) =
4399                    self.forbid_let_reason =>
4400            {
4401                let forbid_let_reason = self.forbid_let_reason;
4402                self.forbid_let_reason =
4403                    Some(diagnostics::ForbiddenLetReason::NotSupportedParentheses(inner.span));
4404                mut_visit::walk_expr(self, e);
4405                self.forbid_let_reason = forbid_let_reason;
4406            }
4407            ExprKind::Assign(ref lhs, ref rhs, span) => {
4408                if let ExprKind::Call(_, _) = &lhs.kind {
4409                    fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4410                        fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4411                            match &e.kind {
4412                                ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
4413                                ExprKind::Path(_, path) => Some((depth, path)),
4414                                _ => None,
4415                            }
4416                        }
4417
4418                        inner(e, 0)
4419                    }
4420
4421                    if let Some((depth, path)) = get_path_from_rhs(rhs) {
4422                        // For cases like if Some(_) = x && let Some(_) = y && let Some(_) = z
4423                        // This return let Some(_) = y expression
4424                        fn find_let_some(expr: &Expr) -> Option<&Expr> {
4425                            match &expr.kind {
4426                                ExprKind::Let(..) => Some(expr),
4427
4428                                ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
4429                                    find_let_some(lhs).or_else(|| find_let_some(rhs))
4430                                }
4431
4432                                _ => None,
4433                            }
4434                        }
4435
4436                        let expr_span = lhs.span.to(path.span);
4437
4438                        if let Some(later_rhs) = find_let_some(rhs)
4439                            && depth > 0
4440                        {
4441                            let guar =
4442                                self.parser.dcx().emit_err(diagnostics::LetChainMissingLet {
4443                                    span: lhs.span,
4444                                    label_span: expr_span,
4445                                    rhs_span: later_rhs.span,
4446                                    sug_span: lhs.span.shrink_to_lo(),
4447                                });
4448
4449                            self.found_incorrect_let_chain = Some(guar);
4450                        }
4451                    }
4452                }
4453
4454                let forbid_let_reason = self.forbid_let_reason;
4455                self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4456                let missing_let = self.missing_let;
4457                if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4458                    && let ExprKind::Path(_, _)
4459                    | ExprKind::Struct(_)
4460                    | ExprKind::Call(_, _)
4461                    | ExprKind::Array(_) = rhs.kind
4462                {
4463                    self.missing_let =
4464                        Some(diagnostics::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4465                }
4466                let comparison = self.comparison;
4467                self.comparison = Some(diagnostics::MaybeComparison { span: span.shrink_to_hi() });
4468                mut_visit::walk_expr(self, e);
4469                self.forbid_let_reason = forbid_let_reason;
4470                self.missing_let = missing_let;
4471                self.comparison = comparison;
4472            }
4473            ExprKind::Unary(_, _)
4474            | ExprKind::Await(_, _)
4475            | ExprKind::Move(_, _)
4476            | ExprKind::Use(_, _)
4477            | ExprKind::AssignOp(_, _, _)
4478            | ExprKind::Range(_, _, _)
4479            | ExprKind::Try(_)
4480            | ExprKind::AddrOf(_, _, _)
4481            | ExprKind::Binary(_, _, _)
4482            | ExprKind::Field(_, _)
4483            | ExprKind::Index(_, _, _)
4484            | ExprKind::Call(_, _)
4485            | ExprKind::MethodCall(_)
4486            | ExprKind::Tup(_)
4487            | ExprKind::Paren(_) => {
4488                let forbid_let_reason = self.forbid_let_reason;
4489                self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4490                mut_visit::walk_expr(self, e);
4491                self.forbid_let_reason = forbid_let_reason;
4492            }
4493            ExprKind::Cast(ref mut op, _)
4494            | ExprKind::Type(ref mut op, _)
4495            | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4496                let forbid_let_reason = self.forbid_let_reason;
4497                self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4498                self.visit_expr(op);
4499                self.forbid_let_reason = forbid_let_reason;
4500            }
4501            ExprKind::Let(_, _, _, Recovered::Yes(_))
4502            | ExprKind::Array(_)
4503            | ExprKind::ConstBlock(_)
4504            | ExprKind::Lit(_)
4505            | ExprKind::If(_, _, _)
4506            | ExprKind::While(_, _, _)
4507            | ExprKind::ForLoop { .. }
4508            | ExprKind::Loop(_, _, _)
4509            | ExprKind::Match(_, _, _)
4510            | ExprKind::Closure(_)
4511            | ExprKind::Block(_, _)
4512            | ExprKind::Gen(_, _, _, _)
4513            | ExprKind::TryBlock(_, _)
4514            | ExprKind::Underscore
4515            | ExprKind::Path(_, _)
4516            | ExprKind::Break(_, _)
4517            | ExprKind::Continue(_)
4518            | ExprKind::Ret(_)
4519            | ExprKind::InlineAsm(_)
4520            | ExprKind::OffsetOf(_, _)
4521            | ExprKind::MacCall(_)
4522            | ExprKind::Struct(_)
4523            | ExprKind::Repeat(_, _)
4524            | ExprKind::Yield(_)
4525            | ExprKind::Yeet(_)
4526            | ExprKind::Become(_)
4527            | ExprKind::IncludedBytes(_)
4528            | ExprKind::FormatArgs(_)
4529            | ExprKind::Err(_)
4530            | ExprKind::DirectConstArg(_)
4531            | ExprKind::Dummy => {
4532                // These would forbid any let expressions they contain already.
4533            }
4534        }
4535        self.depth -= 1;
4536    }
4537}