rustc_parse/parser/
expr.rs

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