compiler/rustc_parse/src/parser/expr.rs RUST 4,329 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,329.
1// ignore-tidy-file-filelength23use core::mem;4use core::ops::{Bound, ControlFlow};56use ast::mut_visit::{self, MutVisitor};7use ast::token::IdentKind;8use ast::{ForLoopKind, MatchKind, Pat, Path, PathSegment, Recovered};9use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};10use rustc_ast::util::case::Case;11use rustc_ast::util::classify;12use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};13use rustc_ast::visit::{Visitor, walk_expr};14use rustc_ast::{15    self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,16    BlockCheckMode, CaptureBy, ClosureBinder, CoroutineKind, DUMMY_NODE_ID, Expr, ExprField,17    ExprKind, FnDecl, FnRetTy, ForLoop, Guard, Label, MacCall, MetaItemLit, Movability, Param,18    RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,19};20use rustc_ast_pretty::pprust;21use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};22use rustc_lint_defs::builtin::BREAK_WITH_LABEL_AND_LOOP;23use rustc_literal_escaper::unescape_char;24use rustc_session::diagnostics::report_lit_error;25use rustc_span::edition::Edition;26use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym};27use thin_vec::{ThinVec, thin_vec};28use tracing::instrument;2930use super::diagnostics::SnapshotParser;31use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};32use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};33use super::{34    AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,35    Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,36};37use crate::{exp, maybe_recover_from_interpolated_ty_qpath};3839pub(super) mod diagnostics;4041#[derive(Debug)]42pub(super) enum DestructuredFloat {43    /// 1e244    Single(Symbol, Span),45    /// 1.46    TrailingDot(Symbol, Span, Span),47    /// 1.2 | 1.2e348    MiddleDot(Symbol, Span, Span, Symbol, Span),49    /// Invalid50    Error,51}5253impl<'a> Parser<'a> {54    /// Parses an expression.55    #[inline]56    pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> {57        self.current_closure.take();58        self.parse_expr_res(Restrictions::empty())59    }60    #[inline]61    pub fn parse_expr_in_let(&mut self) -> PResult<'a, Box<Expr>> {62        self.current_closure.take();63        self.parse_expr_res(Restrictions::IN_LET)64    }65    /// Parses an expression, forcing tokens to be collected.66    pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {67        self.current_closure.take();6869        // If the expression is associative (e.g. `1 + 2`), then any preceding70        // outer attribute actually belongs to the first inner sub-expression.71        // In which case we must use the pre-attr pos to include the attribute72        // in the collected tokens for the outer expression.73        let pre_attr_pos = self.collect_pos();74        let attrs = self.parse_outer_attributes()?;75        self.collect_tokens(76            Some(pre_attr_pos),77            AttrWrapper::empty(),78            ForceCollect::Yes,79            |this, _empty_attrs| {80                let (expr, is_assoc) =81                    this.parse_expr_res_after_attrs(Restrictions::empty(), attrs)?;82                let use_pre_attr_pos =83                    if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };84                Ok((expr, Trailing::No, use_pre_attr_pos))85            },86        )87    }8889    pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {90        self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })91    }9293    /// Parses a sequence of expressions delimited by parentheses.94    fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {95        self.parse_paren_comma_seq(Self::parse_expr).map(|(r, _)| r)96    }9798    /// Parses an expression, subject to the given restrictions.99    #[inline]100    pub(super) fn parse_expr_res(&mut self, r: Restrictions) -> PResult<'a, Box<Expr>> {101        let attrs = self.parse_outer_attributes()?;102        self.parse_expr_res_after_attrs(r, attrs).map(|(expr, _)| expr)103    }104105    /// Same as `parse_expr_res`, but with attributes already pre-parsed.106    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator107    /// followed by a subexpression (e.g. `1 + 2`).108    #[inline]109    pub(super) fn parse_expr_res_after_attrs(110        &mut self,111        r: Restrictions,112        attrs: AttrWrapper,113    ) -> PResult<'a, (Box<Expr>, bool)> {114        self.with_res(r, |this| this.parse_expr_assoc_after_attrs(Bound::Unbounded, attrs))115    }116117    /// Parses an associative expression with operators of at least `min_prec` precedence.118    pub(super) fn parse_expr_assoc(119        &mut self,120        min_prec: Bound<ExprPrecedence>,121    ) -> PResult<'a, Box<Expr>> {122        let attrs = self.parse_outer_attributes()?;123        self.parse_expr_assoc_after_attrs(min_prec, attrs).map(|(expr, _)| expr)124    }125126    /// Same as `parse_expr_assoc`, but with attributes already pre-parsed.127    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator128    /// followed by a subexpression (e.g. `1 + 2`).129    pub(super) fn parse_expr_assoc_after_attrs(130        &mut self,131        min_prec: Bound<ExprPrecedence>,132        attrs: AttrWrapper,133    ) -> PResult<'a, (Box<Expr>, bool)> {134        let lhs = if self.token.is_range_separator() {135            return self.parse_expr_prefix_range(attrs).map(|res| (res, false));136        } else {137            self.parse_expr_prefix(attrs)?138        };139        self.parse_expr_assoc_rest(min_prec, false, lhs)140    }141142    /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators143    /// of at least `min_prec` precedence. The `bool` in the return value indicates if something144    /// was actually parsed.145    pub(super) fn parse_expr_assoc_rest(146        &mut self,147        min_prec: Bound<ExprPrecedence>,148        starts_stmt: bool,149        mut lhs: Box<Expr>,150    ) -> PResult<'a, (Box<Expr>, bool)> {151        let mut parsed_something = false;152        if self.expr_is_complete(&lhs) && !self.recover_from_bin_op_after_complete_stmt_expr(&lhs) {153            return Ok((lhs, parsed_something));154        }155156        self.expected_token_types.insert(TokenType::Operator);157        while let Some(op) = self.check_assoc_op() {158            let lhs_span = self.interpolated_or_expr_span(&lhs);159            let restrictions = if op.node.is_assign_like() {160                self.restrictions & Restrictions::NO_STRUCT_LITERAL161            } else {162                self.restrictions163            };164            let prec = op.node.precedence();165            if match min_prec {166                Bound::Included(min_prec) => prec < min_prec,167                Bound::Excluded(min_prec) => prec <= min_prec,168                Bound::Unbounded => false,169            } {170                break;171            }172173            self.reject_dotdotdot_expr_op();174            self.reject_larrow_expr_op();175176            parsed_something = true;177            self.bump();178179            if op.node.is_comparison()180                && let Some(expr) = self.check_no_chained_comparison(&lhs, &op)?181            {182                return Ok((expr, parsed_something));183            }184185            self.recover_from_strict_eq_op(op);186            self.recover_from_diamond_ne_op();187            self.recover_from_spaceship_cmp_op();188            self.recover_from_postfix_inc_op(&lhs, starts_stmt)?;189            self.recover_from_postfix_dec_op(&lhs, starts_stmt)?;190191            let min_prec = match op.node.fixity() {192                Fixity::Right => Bound::Included(prec),193                Fixity::Left | Fixity::None => Bound::Excluded(prec),194            };195196            let finish_parsing_bin_op = |this: &mut Self| {197                let rhs = this.with_res(restrictions - Restrictions::STMT_EXPR, |this| {198                    this.parse_expr_assoc(min_prec)199                })?;200                let span = this.mk_expr_sp(&lhs, lhs_span, op.span, rhs.span);201                Ok((rhs, span))202            };203204            lhs = match op.node {205                AssocOp::Binary(ast_op) => {206                    let (rhs, span) = finish_parsing_bin_op(self)?;207                    self.mk_expr(span, self.mk_binary(respan(op.span, ast_op), lhs, rhs))208                }209                AssocOp::AssignOp(aop) => {210                    let (rhs, span) = finish_parsing_bin_op(self)?;211                    self.mk_expr(span, self.mk_assign_op(respan(op.span, aop), lhs, rhs))212                }213                AssocOp::Assign => {214                    let (rhs, span) = finish_parsing_bin_op(self)?;215                    self.mk_expr(span, ExprKind::Assign(lhs, rhs, op.span))216                }217                AssocOp::Cast => self.parse_assoc_op_cast(lhs, lhs_span, op.span)?,218                AssocOp::Range(limits) => self.parse_expr_range(min_prec, lhs, limits, op.span)?,219            };220221            if let AssocOp::Range(_) = op.node {222                break;223            }224        }225226        Ok((lhs, parsed_something))227    }228229    /// Possibly translate the current token to an associative operator.230    /// The method does not advance the current token.231    pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {232        let op = AssocOp::from_token(&self.token);233234        // When parsing const expressions, stop parsing when encountering `>`.235        if self.restrictions.contains(Restrictions::CONST_EXPR)236            && let Some(op) = op237            && let AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)238            | AssocOp::AssignOp(AssignOpKind::ShrAssign) = op239        {240            return None;241        }242243        // When recovering patterns as expressions, stop parsing when encountering an244        // assignment `=`, an alternative `|`, or a range `..`.245        if self.restrictions.contains(Restrictions::IS_PAT)246            && let Some(op) = op247            && let AssocOp::Assign248            | AssocOp::AssignOp(_)249            | AssocOp::Binary(BinOpKind::BitOr)250            | AssocOp::Range(_) = op251        {252            return None;253        }254255        if let Some(op) = op {256            return Some(respan(self.token.span, op));257        }258259        self.recover_from_alpha_logic_op()260    }261262    /// Checks if this expression is a successfully parsed statement.263    fn expr_is_complete(&self, e: &Expr) -> bool {264        self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)265    }266267    /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.268    /// The other two variants are handled in `parse_prefix_range_expr` below.269    fn parse_expr_range(270        &mut self,271        min_prec: Bound<ExprPrecedence>,272        lhs: Box<Expr>,273        limits: RangeLimits,274        cur_op_span: Span,275    ) -> PResult<'a, Box<Expr>> {276        let rhs = if self.is_at_start_of_range_notation_rhs() {277            let maybe_lt = self.token;278            Some(279                self.parse_expr_assoc(min_prec)280                    .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,281            )282        } else {283            None284        };285        let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);286        let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);287        let range = self.mk_range(Some(lhs), rhs, limits);288        Ok(self.mk_expr(span, range))289    }290291    fn is_at_start_of_range_notation_rhs(&self) -> bool {292        if self.token.can_begin_expr() {293            // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.294            if self.token == token::OpenBrace {295                return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);296            }297            true298        } else {299            false300        }301    }302303    /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.304    fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {305        if !attrs.is_empty() {306            let err = crate::diagnostics::DotDotRangeAttribute { span: self.token.span };307            self.dcx().emit_err(err);308        }309310        self.reject_dotdotdot_expr_op();311312        debug_assert!(313            self.token.is_range_separator(),314            "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",315            self.token316        );317318        let limits = match self.token.kind {319            token::DotDot => RangeLimits::HalfOpen,320            _ => RangeLimits::Closed,321        };322        let op = AssocOp::from_token(&self.token);323        self.collect_tokens_for_expr(AttrWrapper::empty(), |this, _empty_attrs| {324            let lo = this.token.span;325            let maybe_lt = this.look_ahead(1, |t| t.clone());326            this.bump();327            let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {328                // RHS must be parsed with more associativity than the dots.329                this.parse_expr_assoc(Bound::Excluded(op.unwrap().precedence()))330                    .map(|expr| (lo.to(expr.span), Some(expr)))331                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?332            } else {333                (lo, None)334            };335            let range = this.mk_range(None, opt_end, limits);336            Ok(this.mk_expr(span, range))337        })338    }339340    /// Parses a prefix-unary-operator expr.341    fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {342        let lo = self.token.span;343344        macro_rules! make_it {345            ($this:ident, $attrs:expr, |this, _| $body:expr) => {346                $this.collect_tokens_for_expr($attrs, |$this, attrs| {347                    let (hi, ex) = $body?;348                    Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))349                })350            };351        }352353        let this = self;354355        // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()356        match this.token.uninterpolate().kind {357            // `!expr`358            token::Bang => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)),359            // `~expr`360            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),361            // `-expr`362            token::Minus => {363                make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg))364            }365            // `*expr`366            token::Star => {367                make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref))368            }369            // `&expr` and `&&expr`370            token::And | token::AndAnd => {371                make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo))372            }373            // `+lit`374            token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {375                let mut err = crate::diagnostics::LeadingPlusNotSupported {376                    span: lo,377                    remove_plus: None,378                    add_parentheses: None,379                };380381                // a block on the LHS might have been intended to be an expression instead382                if let Some(sp) =383                    this.psess.complete_stmt_exprs_before_bin_op_lookalike.borrow().get(&lo)384                {385                    err.add_parentheses =386                        Some(crate::diagnostics::ExprParenthesesNeeded::surrounding(*sp));387                } else {388                    err.remove_plus = Some(lo);389                }390                this.dcx().emit_err(err);391392                this.bump(); // `+`393                Ok(this.parse_expr_prefix_common(lo)?.1)394            }395            // Recover from `++x`:396            token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {397                let starts_stmt =398                    this.prev_token == token::Semi || this.prev_token == token::CloseBrace;399                let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));400                // Eat both `+`s.401                this.bump();402                this.bump();403404                let operand = this.parse_expr_dot_or_call(attrs)?;405                return Err(this.report_inc_dec_op(406                    &operand,407                    starts_stmt,408                    diagnostics::IncOrDec::Inc,409                    diagnostics::UnaryFixity::Pre,410                    pre_span,411                ));412            }413            token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {414                make_it!(this, attrs, |this, _| this.recover_not_expr(lo))415            }416            _ => this.parse_expr_dot_or_call(attrs),417        }418    }419420    fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {421        let attrs = self.parse_outer_attributes()?;422        let expr = if self.token.is_range_separator() {423            self.parse_expr_prefix_range(attrs)424        } else {425            self.parse_expr_prefix(attrs)426        }?;427        let span = self.interpolated_or_expr_span(&expr);428        Ok((lo.to(span), expr))429    }430431    fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {432        self.bump(); // `op`433        let (span, expr) = self.parse_expr_prefix_common(lo)?;434        Ok((span, self.mk_unary(op, expr)))435    }436437    /// Recover on `~expr` in favor of `!expr`.438    fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {439        self.dcx().emit_err(crate::diagnostics::TildeAsUnaryOperator(lo));440441        self.parse_expr_unary(lo, UnOp::Not)442    }443444    fn is_mistaken_not_ident_negation(&self) -> bool {445        let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {446            // These tokens can start an expression after `!`, but447            // can't continue an expression after an ident448            token::Ident(name, kind) => token::ident_can_begin_expr(name, t.span, kind),449            token::Literal(..) | token::Pound => true,450            _ => t.is_metavar_expr(),451        };452        self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)453    }454455    /// Recover on `not expr` in favor of `!expr`.456    fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {457        let negated_token = self.look_ahead(1, |t| *t);458459        let sub_diag = if negated_token.is_numeric_lit() {460            crate::diagnostics::NotAsNegationOperatorSub::SuggestNotBitwise461        } else if negated_token.is_bool_lit() {462            crate::diagnostics::NotAsNegationOperatorSub::SuggestNotLogical463        } else {464            crate::diagnostics::NotAsNegationOperatorSub::SuggestNotDefault465        };466467        self.dcx().emit_err(crate::diagnostics::NotAsNegationOperator {468            negated: negated_token.span,469            negated_desc: super::token_descr(&negated_token),470            // Span the `not` plus trailing whitespace to avoid471            // trailing whitespace after the `!` in our suggestion472            sub: sub_diag(473                self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),474            ),475        });476477        self.parse_expr_unary(lo, UnOp::Not)478    }479480    /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.481    fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {482        match self.prev_token.kind {483            token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,484            token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {485                // `expr.span` is the interpolated span, because invisible open486                // and close delims both get marked with the same span, one487                // that covers the entire thing between them. (See488                // `rustc_expand::mbe::transcribe::transcribe`.)489                self.prev_token.span490            }491            _ => expr.span,492        }493    }494495    fn parse_assoc_op_cast(496        &mut self,497        lhs: Box<Expr>,498        lhs_span: Span,499        op_span: Span,500    ) -> PResult<'a, Box<Expr>> {501        let mk_expr = |this: &mut Self, rhs: Box<Ty>| {502            let span = this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);503            this.mk_expr(span, ExprKind::Cast(lhs, rhs))504        };505506        // Save the state of the parser before parsing type normally, in case there is a507        // LessThan comparison after this cast.508        let parser_snapshot_before_type = self.clone();509        let cast_expr = match self.parse_as_cast_ty() {510            Ok(rhs) => mk_expr(self, rhs),511            Err(type_err) => {512                if !self.may_recover() {513                    return Err(type_err);514                }515516                // Rewind to before attempting to parse the type with generics, to recover517                // from situations like `x as usize < y` in which we first tried to parse518                // `usize < y` as a type with generic arguments.519                let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);520521                match self.parse_path(PathStyle::Expr) {522                    Ok(path) => {523                        let span_after_type = parser_snapshot_after_type.token.span;524                        let expr =525                            mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path.clone())));526527                        let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);528                        match self.token.kind {529                            token::Lt => self.dcx().emit_err(530                                crate::diagnostics::ComparisonInterpretedAsGeneric {531                                    comparison: self.token.span,532                                    r#type: pprust::path_to_string(&path),533                                    args: args_span,534                                    suggestion:535                                        crate::diagnostics::ComparisonInterpretedAsGenericSugg {536                                            left: expr.span.shrink_to_lo(),537                                            right: expr.span.shrink_to_hi(),538                                        },539                                },540                            ),541                            token::Shl => {542                                self.dcx().emit_err(crate::diagnostics::ShiftInterpretedAsGeneric {543                                    shift: self.token.span,544                                    r#type: pprust::path_to_string(&path),545                                    args: args_span,546                                    suggestion: crate::diagnostics::ShiftInterpretedAsGenericSugg {547                                        left: expr.span.shrink_to_lo(),548                                        right: expr.span.shrink_to_hi(),549                                    },550                                })551                            }552                            _ => {553                                // We can end up here even without `<` being the next token, for554                                // example because `parse_ty_no_plus` returns `Err` on keywords,555                                // but `parse_path` returns `Ok` on them due to error recovery.556                                // Return original error and parser state.557                                *self = parser_snapshot_after_type;558                                return Err(type_err);559                            }560                        };561562                        // Successfully parsed the type path leaving a `<` yet to parse.563                        type_err.cancel();564565                        // Keep `x as usize` as an expression in AST and continue parsing.566                        expr567                    }568                    Err(path_err) => {569                        // Couldn't parse as a path, return original error and parser state.570                        path_err.cancel();571                        *self = parser_snapshot_after_type;572                        return Err(type_err);573                    }574                }575            }576        };577578        // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)579        // after a cast. If one is present, emit an error then return a valid580        // parse tree; For something like `&x as T[0]` will be as if it was581        // written `((&x) as T)[0]`.582583        let span = cast_expr.span;584        let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;585586        // Check if an illegal postfix operator has been added after the cast.587        // If the resulting expression is not a cast, it is an illegal postfix operator.588        if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {589            let kind = match with_postfix.kind {590                ExprKind::Index(..) => "indexing",591                ExprKind::Try(_) => "`?`",592                ExprKind::Field(_, _) => "a field access",593                ExprKind::MethodCall(_) => "a method call",594                ExprKind::Call(_, _) => "a function call",595                ExprKind::Await(_, _) => "`.await`",596                ExprKind::Use(_, _) => "`.use`",597                ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",598                ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",599                ExprKind::Err(_) => return Ok(with_postfix),600                _ => unreachable!(601                    "did not expect {:?} as an illegal postfix operator following cast",602                    with_postfix.kind603                ),604            };605            self.dcx()606                .struct_span_err(span, format!("cast cannot be followed by {kind}"))607                .with_multipart_suggestion(608                    "try surrounding the expression in parentheses",609                    vec![610                        (span.shrink_to_lo(), "(".to_string()),611                        (span.shrink_to_hi(), ")".to_string()),612                    ],613                    Applicability::MachineApplicable,614                )615                .emit();616        };617        Ok(with_postfix)618    }619620    /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.621    fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {622        self.expect_and()?;623        let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);624        let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.625        let (borrow_kind, mutbl) = self.parse_borrow_modifiers();626        let (span, expr) = self.parse_expr_prefix_common(lo)?;627        if let Some(lt) = lifetime {628            self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));629        }630631        // Add expected tokens if we parsed `&raw` as an expression.632        // This will make sure we see "expected `const`, `mut`", and633        // guides recovery in case we write `&raw expr`.634        if borrow_kind == ast::BorrowKind::Ref635            && mutbl == ast::Mutability::Not636            && matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw)637        {638            self.expected_token_types.insert(TokenType::KwMut);639            self.expected_token_types.insert(TokenType::KwConst);640        }641642        Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))643    }644645    fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {646        self.dcx().emit_err(crate::diagnostics::LifetimeInBorrowExpression {647            span,648            lifetime_span: lt_span,649        });650    }651652    /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.653    fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {654        if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {655            // `raw [ const | mut ]`.656            let found_raw = self.eat_keyword(exp!(Raw));657            assert!(found_raw);658            let mutability = self.parse_mut_or_const().unwrap();659            (ast::BorrowKind::Raw, mutability)660        } else {661            match self.parse_pin_and_mut() {662                // `mut?`663                (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),664                // `pin [ const | mut ]`.665                // `pin` has been gated in `self.parse_pin_and_mut()` so we don't666                // need to gate it here.667                (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),668            }669        }670    }671672    /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.673    fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {674        self.collect_tokens_for_expr(attrs, |this, attrs| {675            let base = this.parse_expr_bottom()?;676            let span = this.interpolated_or_expr_span(&base);677            this.parse_expr_dot_or_call_with(attrs, base, span)678        })679    }680681    pub(super) fn parse_expr_dot_or_call_with(682        &mut self,683        mut attrs: ast::AttrVec,684        mut e: Box<Expr>,685        lo: Span,686    ) -> PResult<'a, Box<Expr>> {687        let mut res = loop {688            let has_question = if self.prev_token.is_keyword(kw::Return) {689                // We are using noexpect here because we don't expect a `?` directly after690                // a `return` which could be suggested otherwise.691                self.eat_noexpect(&token::Question)692            } else {693                self.eat(exp!(Question))694            };695            if has_question {696                // `expr?`697                e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));698                continue;699            }700            let has_dot = if self.prev_token.is_keyword(kw::Return) {701                // We are using noexpect here because we don't expect a `.` directly after702                // a `return` which could be suggested otherwise.703                self.eat_noexpect(&token::Dot)704            } else if self.token == TokenKind::RArrow && self.may_recover() {705                // Recovery for `expr->suffix`.706                self.bump();707                let span = self.prev_token.span;708                self.dcx().emit_err(crate::diagnostics::ExprRArrowCall { span });709                true710            } else {711                self.eat(exp!(Dot))712            };713            if has_dot {714                // expr.f715                e = self.parse_dot_suffix_expr(lo, e)?;716                continue;717            }718            if self.expr_is_complete(&e) {719                break Ok(e);720            }721            e = match self.token.kind {722                token::OpenParen => self.parse_expr_fn_call(lo, e),723                token::OpenBracket => self.parse_expr_index(lo, e)?,724                _ => break Ok(e),725            }726        };727728        // Stitch the list of outer attributes onto the return value. A little729        // bit ugly, but the best way given the current code structure.730        if !attrs.is_empty()731            && let Ok(expr) = &mut res732        {733            mem::swap(&mut expr.attrs, &mut attrs);734            expr.attrs.extend(attrs)735        }736        res737    }738739    pub(super) fn parse_dot_suffix_expr(740        &mut self,741        lo: Span,742        base: Box<Expr>,743    ) -> PResult<'a, Box<Expr>> {744        // At this point we've consumed something like `expr.` and `self.token` holds the token745        // after the dot.746        match self.token.uninterpolate().kind {747            token::Ident(..) => self.parse_dot_suffix(base, lo),748            token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {749                let ident_span = self.token.span;750                self.bump();751                Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))752            }753            token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {754                Ok(match self.break_up_float(symbol, self.token.span) {755                    // 1e2756                    DestructuredFloat::Single(sym, _sp) => {757                        // `foo.1e2`: a single complete dot access, fully consumed. We end up with758                        // the `1e2` token in `self.prev_token` and the following token in759                        // `self.token`.760                        let ident_span = self.token.span;761                        self.bump();762                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)763                    }764                    // 1.765                    DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {766                        // `foo.1.`: a single complete dot access and the start of another.767                        // We end up with the `sym` (`1`) token in `self.prev_token` and a dot in768                        // `self.token`.769                        assert!(suffix.is_none());770                        self.token = Token::new(token::Ident(sym, IdentKind::Normal), ident_span);771                        self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));772                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)773                    }774                    // 1.2 | 1.2e3775                    DestructuredFloat::MiddleDot(776                        sym1,777                        ident1_span,778                        _dot_span,779                        sym2,780                        ident2_span,781                    ) => {782                        // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with783                        // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following784                        // token in `self.token`.785                        let next_token2 =786                            Token::new(token::Ident(sym2, IdentKind::Normal), ident2_span);787                        self.bump_with((next_token2, self.token_spacing));788                        self.bump();789                        let base1 =790                            self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);791                        self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)792                    }793                    DestructuredFloat::Error => base,794                })795            }796            _ => {797                self.error_unexpected_after_dot();798                Ok(base)799            }800        }801    }802803    fn error_unexpected_after_dot(&self) {804        let actual = super::token_descr(&self.token);805        let span = self.token.span;806        let sm = self.psess.source_map();807        let (span, actual) = match (&self.token.kind, self.subparser_name) {808            (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {809                (span.shrink_to_hi(), format!("`{}`", snippet))810            }811            (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {812                // No need to report an error. This case will only occur when parsing a pasted813                // metavariable, and we should have emitted an error when parsing the macro call in814                // the first place. E.g. in this code:815                // ```816                // macro_rules! m { ($e:expr) => { $e }; }817                //818                // fn main() {819                //     let f = 1;820                //     m!(f.);821                // }822                // ```823                // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't824                // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`825                // represent the invisible delimiters).826                self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");827                return;828            }829            _ => (span, actual),830        };831        self.dcx().emit_err(crate::diagnostics::UnexpectedTokenAfterDot { span, actual });832    }833834    /// We need an identifier or integer, but the next token is a float.835    /// Break the float into components to extract the identifier or integer.836    ///837    /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.838    //839    // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2840    //  parts unless those parts are processed immediately. `TokenCursor` should either841    //  support pushing "future tokens" (would be also helpful to `break_and_eat`), or842    //  we should break everything including floats into more basic proc-macro style843    //  tokens in the lexer (probably preferable).844    pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {845        #[derive(Debug)]846        enum FloatComponent {847            IdentLike(String),848            Punct(char),849        }850        use FloatComponent::*;851852        let float_str = float.as_str();853        let mut components = Vec::new();854        let mut ident_like = String::new();855        for c in float_str.chars() {856            if c == '_' || c.is_ascii_alphanumeric() {857                ident_like.push(c);858            } else if matches!(c, '.' | '+' | '-') {859                if !ident_like.is_empty() {860                    components.push(IdentLike(mem::take(&mut ident_like)));861                }862                components.push(Punct(c));863            } else {864                panic!("unexpected character in a float token: {c:?}")865            }866        }867        if !ident_like.is_empty() {868            components.push(IdentLike(ident_like));869        }870871        // With proc macros the span can refer to anything, the source may be too short,872        // or too long, or non-ASCII. It only makes sense to break our span into components873        // if its underlying text is identical to our float literal.874        let can_take_span_apart =875            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();876877        match &*components {878            // 1e2879            [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span),880            // 1.881            [IdentLike(left), Punct('.')] => {882                let (left_span, dot_span) = if can_take_span_apart() {883                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));884                    let dot_span = span.with_lo(left_span.hi());885                    (left_span, dot_span)886                } else {887                    (span, span)888                };889                let left = Symbol::intern(left);890                DestructuredFloat::TrailingDot(left, left_span, dot_span)891            }892            // 1.2 | 1.2e3893            [IdentLike(left), Punct('.'), IdentLike(right)] => {894                let (left_span, dot_span, right_span) = if can_take_span_apart() {895                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));896                    let dot_span =897                        span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));898                    let right_span = span.with_lo(dot_span.hi());899                    (left_span, dot_span, right_span)900                } else {901                    (span, span, span)902                };903                let left = Symbol::intern(left);904                let right = Symbol::intern(right);905                DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)906            }907            // 1e+ | 1e- (recovered)908            [IdentLike(_), Punct('+' | '-')] |909            // 1e+2 | 1e-2910            [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |911            // 1.2e+ | 1.2e-912            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |913            // 1.2e+3 | 1.2e-3914            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {915                // See the FIXME about `TokenCursor` above.916                self.error_unexpected_after_dot();917                DestructuredFloat::Error918            }919            _ => panic!("unexpected components in a float token: {components:?}"),920        }921    }922923    /// Parse the field access used in offset_of, matched by `$(e:expr)+`.924    /// Currently returns a list of idents. However, it should be possible in925    /// future to also do array indices, which might be arbitrary expressions.926    pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, ThinVec<Ident>> {927        let mut fields = ThinVec::new();928        let mut trailing_dot = None;929930        loop {931            // This is expected to use a metavariable $(args:expr)+, but the builtin syntax932            // could be called directly. Calling `parse_expr` allows this function to only933            // consider `Expr`s.934            let expr = self.parse_expr()?;935            let mut current = &expr;936            let start_idx = fields.len();937            loop {938                match current.kind {939                    ExprKind::Field(ref left, right) => {940                        // Field access is read right-to-left.941                        fields.insert(start_idx, right);942                        trailing_dot = None;943                        current = left;944                    }945                    // Parse this both to give helpful error messages and to946                    // verify it can be done with this parser setup.947                    ExprKind::Index(ref left, ref _right, span) => {948                        self.dcx().emit_err(crate::diagnostics::ArrayIndexInOffsetOf(span));949                        current = left;950                    }951                    ExprKind::Lit(token::Lit {952                        kind: token::Float | token::Integer,953                        symbol,954                        suffix,955                    }) => {956                        if let Some(suffix) = suffix {957                            self.dcx().emit_err(958                                crate::diagnostics::InvalidLiteralSuffixOnTupleIndex {959                                    span: current.span,960                                    suffix,961                                },962                            );963                        }964                        match self.break_up_float(symbol, current.span) {965                            // 1e2966                            DestructuredFloat::Single(sym, sp) => {967                                trailing_dot = None;968                                fields.insert(start_idx, Ident::new(sym, sp));969                            }970                            // 1.971                            DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {972                                assert!(suffix.is_none());973                                trailing_dot = Some(dot_span);974                                fields.insert(start_idx, Ident::new(sym, sym_span));975                            }976                            // 1.2 | 1.2e3977                            DestructuredFloat::MiddleDot(978                                symbol1,979                                span1,980                                _dot_span,981                                symbol2,982                                span2,983                            ) => {984                                trailing_dot = None;985                                fields.insert(start_idx, Ident::new(symbol2, span2));986                                fields.insert(start_idx, Ident::new(symbol1, span1));987                            }988                            DestructuredFloat::Error => {989                                trailing_dot = None;990                                fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));991                            }992                        }993                        break;994                    }995                    ExprKind::Path(None, Path { ref segments, .. }) => {996                        match &segments[..] {997                            [PathSegment { ident, args: None, .. }] => {998                                trailing_dot = None;999                                fields.insert(start_idx, *ident)1000                            }1001                            _ => {1002                                self.dcx()1003                                    .emit_err(crate::diagnostics::InvalidOffsetOf(current.span));1004                                break;1005                            }1006                        }1007                        break;1008                    }1009                    _ => {1010                        self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(current.span));1011                        break;1012                    }1013                }1014            }10151016            if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {1017                break;1018            } else if trailing_dot.is_none() {1019                // This loop should only repeat if there is a trailing dot.1020                self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(self.token.span));1021                break;1022            }1023        }1024        if let Some(dot) = trailing_dot {1025            self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(dot));1026        }1027        Ok(fields.into_iter().collect())1028    }10291030    fn mk_expr_tuple_field_access(1031        &self,1032        lo: Span,1033        ident_span: Span,1034        base: Box<Expr>,1035        field: Symbol,1036        suffix: Option<Symbol>,1037    ) -> Box<Expr> {1038        if let Some(suffix) = suffix {1039            self.dcx().emit_err(crate::diagnostics::InvalidLiteralSuffixOnTupleIndex {1040                span: ident_span,1041                suffix,1042            });1043        }1044        self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))1045    }10461047    /// Parse a function call expression, `expr(...)`.1048    fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {1049        let snapshot = if self.token == token::OpenParen {1050            Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))1051        } else {1052            None1053        };1054        let open_paren = self.token.span;1055        let call_depth = self.token_cursor.depth();10561057        let seq = match self.parse_expr_paren_seq() {1058            Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),1059            Err(err)1060                if self.is_expected_raw_ref_mut() && self.token_cursor.depth() == call_depth =>1061            {1062                let guar = err.emit_err();1063                // Preserve the call expression so later passes can still diagnose the callee,1064                // while treating the malformed `&raw <expr>` argument as an error expression.1065                let args = self.recover_raw_ref_call_args(guar);1066                return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));1067            }1068            Err(err) => Err(err),1069        };1070        match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {1071            Ok(expr) => expr,1072            Err(err) => self.recover_seq_parse_error(exp!(OpenParen), exp!(CloseParen), lo, err),1073        }1074    }10751076    fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {1077        let err_span = self.prev_token.span.to(self.token.span);1078        let mut args = thin_vec![self.mk_expr_err(err_span, guar)];1079        while !self.token.kind.is_close_delim_or_eof() {1080            if self.eat(exp!(Comma)) {1081                if !self.token.kind.is_close_delim_or_eof() {1082                    args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));1083                }1084            } else {1085                self.parse_token_tree();1086            }1087        }1088        let _ = self.eat(exp!(CloseParen));1089        args1090    }10911092    /// If we encounter a parser state that looks like the user has written a `struct` literal with1093    /// parentheses instead of braces, recover the parser state and provide suggestions.1094    #[instrument(skip(self, seq, snapshot), level = "trace")]1095    fn maybe_recover_struct_lit_bad_delims(1096        &mut self,1097        lo: Span,1098        open_paren: Span,1099        seq: PResult<'a, Box<Expr>>,1100        snapshot: Option<(SnapshotParser<'a>, ExprKind)>,1101    ) -> PResult<'a, Box<Expr>> {1102        match (self.may_recover(), seq, snapshot) {1103            (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {1104                snapshot.bump(); // `(`1105                match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {1106                    Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {1107                        // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest1108                        // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.1109                        self.restore_snapshot(snapshot);1110                        let close_paren = self.prev_token.span;1111                        let span = lo.to(close_paren);1112                        // filter shorthand fields1113                        let fields: Vec<_> =1114                            fields.into_iter().filter(|field| !field.is_shorthand).collect();11151116                        let guar = if !fields.is_empty() &&1117                            // `token.kind` should not be compared here.1118                            // This is because the `snapshot.token.kind` is treated as the same as1119                            // that of the open delim in `TokenTreesReader::parse_token_tree`, even1120                            // if they are different.1121                            self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")1122                        {1123                            err.cancel();1124                            let type_str = pprust::path_to_string(&path);1125                            self.dcx().emit_err(crate::diagnostics::ParenthesesWithStructFields {1126                                span,1127                                braces_for_struct: crate::diagnostics::BracesForStructLiteral {1128                                    first: open_paren,1129                                    second: close_paren,1130                                    r#type: type_str.clone(),1131                                },1132                                no_fields_for_fn: crate::diagnostics::NoFieldsForFnCall {1133                                    r#type: type_str,1134                                    fields: fields1135                                        .into_iter()1136                                        .map(|field| field.span.until(field.expr.span))1137                                        .collect(),1138                                },1139                            })1140                        } else {1141                            err.emit_err()1142                        };1143                        Ok(self.mk_expr_err(span, guar))1144                    }1145                    Ok(_) => Err(err),1146                    Err(err2) => {1147                        err2.cancel();1148                        Err(err)1149                    }1150                }1151            }1152            (_, seq, _) => seq,1153        }1154    }11551156    /// Parse an indexing expression `expr[...]`.1157    fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {1158        let prev_token = self.prev_token;1159        let open_delim_span = self.token.span;1160        self.bump(); // `[`1161        let index = self.parse_expr()?;1162        self.suggest_missing_semicolon_before_array(prev_token.span, open_delim_span)?;1163        self.expect(exp!(CloseBracket)).map_err(|mut err| {1164            if prev_token.is_non_reserved_ident() {1165                err.span_suggestion_verbose(1166                    prev_token.span.shrink_to_hi(),1167                    "you might have meant to call a macro",1168                    "!".to_string(),1169                    Applicability::MaybeIncorrect,1170                );1171            }1172            err1173        })?;1174        Ok(self.mk_expr(1175            lo.to(self.prev_token.span),1176            self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),1177        ))1178    }11791180    /// Assuming we have just parsed `.`, continue parsing into an expression.1181    fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {1182        if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) {1183            return Ok(self.mk_await_expr(self_arg, lo));1184        }11851186        if self.eat_keyword(exp!(Use)) {1187            let use_span = self.prev_token.span;1188            self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);1189            return Ok(self.mk_use_expr(self_arg, lo));1190        }11911192        // Post-fix match1193        if self.eat_keyword(exp!(Match)) {1194            let match_span = self.prev_token.span;1195            self.psess.gated_spans.gate(sym::postfix_match, match_span);1196            return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);1197        }11981199        // Parse a postfix `yield`.1200        if self.eat_keyword(exp!(Yield)) {1201            let yield_span = self.prev_token.span;1202            self.psess.gated_spans.gate(sym::yield_expr, yield_span);1203            return Ok(1204                self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))1205            );1206        }12071208        let fn_span_lo = self.token.span;1209        let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;1210        self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);1211        self.check_turbofish_missing_angle_brackets(&mut seg);12121213        if self.check(exp!(OpenParen)) {1214            // Method call `expr.f()`1215            let args = self.parse_expr_paren_seq()?;1216            let fn_span = fn_span_lo.to(self.prev_token.span);1217            let span = lo.to(self.prev_token.span);1218            Ok(self.mk_expr(1219                span,1220                ExprKind::MethodCall(Box::new(ast::MethodCall {1221                    seg,1222                    receiver: self_arg,1223                    args,1224                    span: fn_span,1225                })),1226            ))1227        } else {1228            // Field access `expr.f`1229            let span = lo.to(self.prev_token.span);1230            if let Some(args) = seg.args {1231                // See `StashKey::GenericInFieldExpr` for more info on why we stash this.1232                self.dcx()1233                    .create_err(crate::diagnostics::FieldExpressionWithGeneric(args.span()))1234                    .stash(seg.ident.span, StashKey::GenericInFieldExpr);1235            }12361237            Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))1238        }1239    }12401241    /// At the bottom (top?) of the precedence hierarchy,1242    /// Parses things like parenthesized exprs, macros, `return`, etc.1243    ///1244    /// N.B., this does not parse outer attributes, and is private because it only works1245    /// correctly if called from `parse_expr_dot_or_call`.1246    fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {1247        maybe_recover_from_interpolated_ty_qpath!(self, true);12481249        let span = self.token.span;1250        if let Some(expr) = self.eat_metavar_seq_with_matcher(1251            |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),1252            |this| {1253                // Force collection (as opposed to just `parse_expr`) is required to avoid the1254                // attribute duplication seen in #138478.1255                let expr = this.parse_expr_force_collect();1256                // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly1257                // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line1258                // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in1259                // `compiler/rustc_index/src/bit_set/tests.rs`.1260                if this.token.kind == token::Comma {1261                    this.bump();1262                }1263                expr1264            },1265        ) {1266            return Ok(expr);1267        } else if let Some(lit) =1268            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())1269        {1270            return Ok(lit);1271        } else if let Some(block) =1272            self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())1273        {1274            return Ok(self.mk_expr(span, ExprKind::Block(block, None)));1275        } else if let Some(path) =1276            self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))1277        {1278            return Ok(self.mk_expr(span, ExprKind::Path(None, path)));1279        }12801281        // Outer attributes are already parsed and will be1282        // added to the return value after the fact.12831284        let restrictions = self.restrictions;1285        self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {1286            // Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.1287            let lo = this.token.span;1288            if let token::Literal(_) = this.token.kind {1289                // This match arm is a special-case of the `_` match arm below and1290                // could be removed without changing functionality, but it's faster1291                // to have it here, especially for programs with large constants.1292                this.parse_expr_lit()1293            } else if this.check(exp!(OpenParen)) {1294                this.parse_expr_tuple_parens(restrictions)1295            } else if this.check(exp!(OpenBrace)) {1296                if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {1297                    return Ok(expr);1298                }1299                if let Some(arr) = this.recover_from_c_array(lo) {1300                    return Ok(arr);1301                }1302                this.parse_expr_block(None, lo, BlockCheckMode::Default)1303            } else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {1304                this.parse_expr_closure().map_err(|mut err| {1305                    // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`1306                    // then suggest parens around the lhs.1307                    if let Some(sp) =1308                        this.psess.complete_stmt_exprs_before_bin_op_lookalike.borrow().get(&lo)1309                    {1310                        err.subdiagnostic(crate::diagnostics::ExprParenthesesNeeded::surrounding(1311                            *sp,1312                        ));1313                    }1314                    err1315                })1316            } else if this.check(exp!(OpenBracket)) {1317                this.parse_expr_array_or_repeat(exp!(CloseBracket))1318            } else if this.is_builtin() {1319                this.parse_expr_builtin()1320            } else if this.check_path() {1321                this.parse_expr_path_start()1322            } else if this.token.is_keyword(kw::Move)1323                && this.look_ahead(1, |t| *t == token::OpenParen)1324            {1325                this.parse_expr_move()1326            } else if this.check_keyword(exp!(Move))1327                || this.check_keyword(exp!(Use))1328                || this.check_keyword(exp!(Static))1329                || this.check_const_closure()1330            {1331                this.parse_expr_closure()1332            } else if this.eat_keyword(exp!(If)) {1333                this.parse_expr_if()1334            } else if this.check_keyword(exp!(For)) {1335                if this.choose_generics_over_qpath(1) {1336                    this.parse_expr_closure()1337                } else {1338                    assert!(this.eat_keyword(exp!(For)));1339                    this.parse_expr_for(None, lo)1340                }1341            } else if this.eat_keyword(exp!(While)) {1342                this.parse_expr_while(None, lo)1343            } else if let Some(label) = this.eat_label() {1344                this.parse_expr_labeled(label, true)1345            } else if this.eat_keyword(exp!(Loop)) {1346                this.parse_expr_loop(None, lo).map_err(|mut err| {1347                    err.span_label(lo, "while parsing this `loop` expression");1348                    err1349                })1350            } else if this.eat_keyword(exp!(Match)) {1351                this.parse_expr_match().map_err(|mut err| {1352                    err.span_label(lo, "while parsing this `match` expression");1353                    err1354                })1355            } else if this.eat_keyword(exp!(Unsafe)) {1356                this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(1357                    |mut err| {1358                        err.span_label(lo, "while parsing this `unsafe` expression");1359                        err1360                    },1361                )1362            } else if this.check_inline_const(0) {1363                this.parse_const_block(lo, false)1364            } else if this.may_recover() && this.is_do_catch_block() {1365                this.recover_do_catch()1366            } else if this.is_try_block() {1367                this.expect_keyword(exp!(Try))?;1368                this.parse_try_block(lo)1369            } else if this.eat_keyword(exp!(Return)) {1370                this.parse_expr_return()1371            } else if this.eat_keyword(exp!(Continue)) {1372                this.parse_expr_continue(lo)1373            } else if this.eat_keyword(exp!(Break)) {1374                this.parse_expr_break()1375            } else if this.eat_keyword(exp!(Yield)) {1376                this.parse_expr_yield()1377            } else if this.is_do_yeet() {1378                this.parse_expr_yeet()1379            } else if this.eat_keyword(exp!(Become)) {1380                this.parse_expr_become()1381            } else if this.check_keyword(exp!(Let)) {1382                this.parse_expr_let(restrictions)1383            } else if this.eat_keyword(exp!(Underscore)) {1384                if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {1385                    return Ok(expr);1386                }1387                Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))1388            } else if this.token_uninterpolated_span().at_least_rust_2018() {1389                // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.1390                let at_async = this.check_keyword(exp!(Async));1391                // check for `gen {}` and `gen move {}`1392                // or `async gen {}` and `async gen move {}`1393                // FIXME: (async) gen closures aren't yet parsed.1394                // FIXME(gen_blocks): Parse `gen async` and suggest swap1395                // FIXME(forced_keywords): Allow k#gen blocks prior to Rust 2024, too!1396                if this.token_uninterpolated_span().at_least_rust_2024()1397                    && this.is_gen_block(kw::Gen, at_async as usize)1398                {1399                    this.parse_gen_block()1400                // Check for `async {` and `async move {`,1401                } else if this.is_gen_block(kw::Async, 0) {1402                    this.parse_gen_block()1403                } else if at_async {1404                    this.parse_expr_closure()1405                } else if this.eat_keyword_noexpect(kw::Await) {1406                    this.recover_incorrect_await_syntax(lo)1407                } else {1408                    this.parse_expr_lit()1409                }1410            } else {1411                this.parse_expr_lit()1412            }1413        })1414    }14151416    fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {1417        let lo = self.token.span;1418        match self.parse_opt_token_lit() {1419            Some((token_lit, _)) => {1420                let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));1421                self.maybe_recover_from_bad_qpath(expr)1422            }1423            None => self.try_macro_suggestion(),1424        }1425    }14261427    fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {1428        let lo = self.token.span;1429        self.expect(exp!(OpenParen))?;1430        let (es, trailing_comma) = match self.parse_seq_to_end(1431            exp!(CloseParen),1432            SeqSep::trailing_allowed(exp!(Comma)),1433            |p| p.parse_expr_res(restrictions.intersection(Restrictions::ALLOW_LET)),1434        ) {1435            Ok(x) => x,1436            Err(err) => {1437                return Ok(self.recover_seq_parse_error(1438                    exp!(OpenParen),1439                    exp!(CloseParen),1440                    lo,1441                    err,1442                ));1443            }1444        };1445        let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) {1446            // `(e)` is parenthesized `e`.1447            ExprKind::Paren(es.into_iter().next().unwrap())1448        } else {1449            // `(e,)` is a tuple with only one field, `e`.1450            ExprKind::Tup(es)1451        };1452        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1453        self.maybe_recover_from_bad_qpath(expr)1454    }14551456    fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {1457        let lo = self.token.span;1458        self.bump(); // `[` or other open delim14591460        let kind = if self.eat(close) {1461            // Empty vector1462            ExprKind::Array(ThinVec::new())1463        } else {1464            // Non-empty vector1465            let first_expr = self.parse_expr()?;1466            if self.eat(exp!(Semi)) {1467                // Repeating array syntax: `[ 0; 512 ]`1468                let count = self.parse_expr_anon_const()?;1469                self.expect(close)?;1470                ExprKind::Repeat(first_expr, count)1471            } else if self.eat(exp!(Comma)) {1472                // Vector with two or more elements.1473                let sep = SeqSep::trailing_allowed(exp!(Comma));1474                let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;1475                exprs.insert(0, first_expr);1476                ExprKind::Array(exprs)1477            } else {1478                // Vector with one element1479                self.expect(close)?;1480                ExprKind::Array(thin_vec![first_expr])1481            }1482        };1483        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1484        self.maybe_recover_from_bad_qpath(expr)1485    }14861487    fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {1488        let maybe_eq_tok = self.prev_token;1489        let (qself, path) = if self.eat_lt() {1490            let lt_span = self.prev_token.span;1491            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {1492                // Suggests using '<=' if there is an error parsing qpath when the previous token1493                // is an '=' token. Only emits suggestion if the '<' token and '=' token are1494                // directly adjacent (i.e. '=<')1495                if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {1496                    let eq_lt = maybe_eq_tok.span.to(lt_span);1497                    err.span_suggestion_verbose(1498                        eq_lt,1499                        "you might have meant to write a \"less than or equal to\" comparison",1500                        "<=",1501                        Applicability::Unspecified,1502                    );1503                }1504                err1505            })?;1506            (Some(qself), path)1507        } else {1508            (None, self.parse_path(PathStyle::Expr)?)1509        };15101511        // `!`, as an operator, is prefix, so we know this isn't that.1512        let (span, kind) = if self.eat(exp!(Bang)) {1513            // MACRO INVOCATION expression1514            if qself.is_some() {1515                self.dcx()1516                    .emit_err(crate::diagnostics::MacroInvocationWithQualifiedPath(path.span));1517            }1518            let lo = path.span;1519            let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });1520            (lo.to(self.prev_token.span), ExprKind::MacCall(mac))1521        } else if self.check(exp!(OpenBrace))1522            && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)1523        {1524            if qself.is_some() {1525                self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);1526            }1527            return expr;1528        } else {1529            (path.span, ExprKind::Path(qself, path))1530        };15311532        let expr = self.mk_expr(span, kind);1533        self.maybe_recover_from_bad_qpath(expr)1534    }15351536    /// Parse `'label: $expr`. The label is already parsed.1537    pub(super) fn parse_expr_labeled(1538        &mut self,1539        label_: Label,1540        mut consume_colon: bool,1541    ) -> PResult<'a, Box<Expr>> {1542        let lo = label_.ident.span;1543        let label = Some(label_);1544        let ate_colon = self.eat(exp!(Colon));1545        let tok_sp = self.token.span;1546        let expr = if self.eat_keyword(exp!(While)) {1547            self.parse_expr_while(label, lo)1548        } else if self.eat_keyword(exp!(For)) {1549            self.parse_expr_for(label, lo)1550        } else if self.eat_keyword(exp!(Loop)) {1551            self.parse_expr_loop(label, lo)1552        } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {1553            self.parse_expr_block(label, lo, BlockCheckMode::Default)1554        } else if !ate_colon1555            && self.may_recover()1556            && (self.token.kind.close_delim().is_some() || self.token.is_punct())1557            && could_be_unclosed_char_literal(label_.ident)1558        {1559            let (lit, _) =1560                self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {1561                    self_.dcx().create_err(crate::diagnostics::UnexpectedTokenAfterLabel {1562                        span: self_.token.span,1563                        remove_label: None,1564                        enclose_in_block: None,1565                    })1566                });1567            consume_colon = false;1568            Ok(self.mk_expr(lo, ExprKind::Lit(lit)))1569        } else if !ate_colon1570            && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))1571        {1572            // We're probably inside of a `Path<'a>` that needs a turbofish1573            let guar = self.dcx().emit_err(crate::diagnostics::UnexpectedTokenAfterLabel {1574                span: self.token.span,1575                remove_label: None,1576                enclose_in_block: None,1577            });1578            consume_colon = false;1579            Ok(self.mk_expr_err(lo, guar))1580        } else {1581            let mut err = crate::diagnostics::UnexpectedTokenAfterLabel {1582                span: self.token.span,1583                remove_label: None,1584                enclose_in_block: None,1585            };15861587            // Continue as an expression in an effort to recover on `'label: non_block_expr`.1588            let expr = self.parse_expr().map(|expr| {1589                let span = expr.span;15901591                let found_labeled_breaks = {1592                    struct FindLabeledBreaksVisitor;15931594                    impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {1595                        type Result = ControlFlow<()>;1596                        fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {1597                            if let ExprKind::Break(Some(_label), _) = ex.kind {1598                                ControlFlow::Break(())1599                            } else {1600                                walk_expr(self, ex)1601                            }1602                        }1603                    }16041605                    FindLabeledBreaksVisitor.visit_expr(&expr).is_break()1606                };16071608                // Suggestion involves adding a labeled block.1609                //1610                // If there are no breaks that may use this label, suggest removing the label and1611                // recover to the unmodified expression.1612                if !found_labeled_breaks {1613                    err.remove_label = Some(lo.until(span));16141615                    return expr;1616                }16171618                err.enclose_in_block = Some(crate::diagnostics::UnexpectedTokenAfterLabelSugg {1619                    left: span.shrink_to_lo(),1620                    right: span.shrink_to_hi(),1621                });16221623                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.1624                let stmt = self.mk_stmt(span, StmtKind::Expr(expr));1625                let blk = self.mk_block(thin_vec![stmt], BlockCheckMode::Default, span);1626                self.mk_expr(span, ExprKind::Block(blk, label))1627            });16281629            self.dcx().emit_err(err);1630            expr1631        }?;16321633        if !ate_colon && consume_colon {1634            self.dcx().emit_err(crate::diagnostics::RequireColonAfterLabeledExpression {1635                span: expr.span,1636                label: lo,1637                label_end: lo.between(tok_sp),1638            });1639        }16401641        Ok(expr)1642    }16431644    /// Emit an error when a char is parsed as a lifetime or label because of a missing quote.1645    pub(super) fn recover_unclosed_char<L>(1646        &self,1647        ident: Ident,1648        mk_lit_char: impl FnOnce(Symbol, Span) -> L,1649        err: impl FnOnce(&Self) -> Diag<'a>,1650    ) -> L {1651        assert!(could_be_unclosed_char_literal(ident));1652        self.dcx()1653            .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {1654                err.span_suggestion_verbose(1655                    ident.span.shrink_to_hi(),1656                    "add `'` to close the char literal",1657                    "'",1658                    Applicability::MaybeIncorrect,1659                );1660            })1661            .unwrap_or_else(|| {1662                err(self)1663                    .with_span_suggestion_verbose(1664                        ident.span.shrink_to_hi(),1665                        "add `'` to close the char literal",1666                        "'",1667                        Applicability::MaybeIncorrect,1668                    )1669                    .emit_err()1670            });1671        let name = ident.without_first_quote().name;1672        mk_lit_char(name, ident.span)1673    }16741675    /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.1676    fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {1677        let lo = self.token.span;16781679        self.bump(); // `do`1680        self.bump(); // `catch`16811682        let span = lo.to(self.prev_token.span);1683        self.dcx().emit_err(crate::diagnostics::DoCatchSyntaxRemoved { span });16841685        self.parse_try_block(lo)1686    }16871688    /// Parse an expression if the token can begin one.1689    fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {1690        Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })1691    }16921693    /// Parse `"return" expr?`.1694    fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {1695        let lo = self.prev_token.span;1696        let kind = ExprKind::Ret(self.parse_expr_opt()?);1697        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1698        self.maybe_recover_from_bad_qpath(expr)1699    }17001701    /// Parse `"do" "yeet" expr?`.1702    fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {1703        let lo = self.token.span;17041705        self.bump(); // `do`1706        self.bump(); // `yeet`17071708        let kind = ExprKind::Yeet(self.parse_expr_opt()?);17091710        let span = lo.to(self.prev_token.span);1711        self.psess.gated_spans.gate(sym::yeet_expr, span);1712        let expr = self.mk_expr(span, kind);1713        self.maybe_recover_from_bad_qpath(expr)1714    }17151716    /// Parse `"become" expr`, with `"become"` token already eaten.1717    fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {1718        let lo = self.prev_token.span;1719        let kind = ExprKind::Become(self.parse_expr()?);1720        let span = lo.to(self.prev_token.span);1721        self.psess.gated_spans.gate(sym::explicit_tail_calls, span);1722        let expr = self.mk_expr(span, kind);1723        self.maybe_recover_from_bad_qpath(expr)1724    }17251726    /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.1727    /// If the label is followed immediately by a `:` token, the label and `:` are1728    /// parsed as part of the expression (i.e. a labeled loop). The language team has1729    /// decided in #87026 to require parentheses as a visual aid to avoid confusion if1730    /// the break expression of an unlabeled break is a labeled loop (as in1731    /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value1732    /// expression only gets a warning for compatibility reasons; and a labeled break1733    /// with a labeled loop does not even get a warning because there is no ambiguity.1734    fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {1735        let lo = self.prev_token.span;1736        let mut label = self.eat_label();1737        let kind = if self.token == token::Colon1738            && let Some(label) = label.take()1739        {1740            // The value expression can be a labeled loop, see issue #86948, e.g.:1741            // `loop { break 'label: loop { break 'label 42; }; }`1742            let lexpr = self.parse_expr_labeled(label, true)?;1743            self.dcx().emit_err(crate::diagnostics::LabeledLoopInBreak {1744                span: lexpr.span,1745                sub: crate::diagnostics::WrapInParentheses::Expression {1746                    left: lexpr.span.shrink_to_lo(),1747                    right: lexpr.span.shrink_to_hi(),1748                },1749            });1750            Some(lexpr)1751        } else if self.token != token::OpenBrace1752            || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)1753        {1754            let mut expr = self.parse_expr_opt()?;1755            if let Some(expr) = &mut expr {1756                if label.is_some()1757                    && match &expr.kind {1758                        ExprKind::While(_, _, None)1759                        | ExprKind::ForLoop(ForLoop { label: None, .. })1760                        | ExprKind::Loop(_, None, _) => true,1761                        ExprKind::Block(block, None) => {1762                            matches!(block.rules, BlockCheckMode::Default)1763                        }1764                        _ => false,1765                    }1766                {1767                    let span = expr.span;1768                    self.psess.buffer_lint(1769                        BREAK_WITH_LABEL_AND_LOOP,1770                        lo.to(expr.span),1771                        ast::CRATE_NODE_ID,1772                        crate::diagnostics::BreakWithLabelAndLoop {1773                            sub: crate::diagnostics::BreakWithLabelAndLoopSub {1774                                left: span.shrink_to_lo(),1775                                right: span.shrink_to_hi(),1776                            },1777                        },1778                    );1779                }17801781                // Recover `break label aaaaa`1782                if self.may_recover()1783                    && let ExprKind::Path(None, p) = &expr.kind1784                    && let [segment] = &*p.segments1785                    && let &ast::PathSegment { ident, args: None, .. } = segment1786                    && let Some(next) = self.parse_expr_opt()?1787                {1788                    label = Some(self.recover_ident_into_label(ident));1789                    *expr = next;1790                }1791            }17921793            expr1794        } else {1795            None1796        };1797        let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));1798        self.maybe_recover_from_bad_qpath(expr)1799    }18001801    /// Parse `"continue" label?`.1802    fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {1803        let mut label = self.eat_label();18041805        // Recover `continue label` -> `continue 'label`1806        if self.may_recover()1807            && label.is_none()1808            && let Some((ident, _)) = self.token.ident()1809        {1810            self.bump();1811            label = Some(self.recover_ident_into_label(ident));1812        }18131814        let kind = ExprKind::Continue(label);1815        Ok(self.mk_expr(lo.to(self.prev_token.span), kind))1816    }18171818    /// Parse `"yield" expr?`.1819    fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {1820        let lo = self.prev_token.span;1821        let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));1822        let span = lo.to(self.prev_token.span);1823        self.psess.gated_spans.gate(sym::yield_expr, span);1824        let expr = self.mk_expr(span, kind);1825        self.maybe_recover_from_bad_qpath(expr)1826    }18271828    /// Parse `builtin # ident(args,*)`.1829    fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> {1830        self.parse_builtin(|this, lo, ident| {1831            Ok(match ident.name {1832                sym::offset_of => Some(this.parse_expr_offset_of(lo)?),1833                sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),1834                sym::wrap_binder => {1835                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)1836                }1837                sym::unwrap_binder => {1838                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)1839                }1840                _ => None,1841            })1842        })1843    }18441845    pub(crate) fn parse_builtin<T>(1846        &mut self,1847        parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,1848    ) -> PResult<'a, T> {1849        let lo = self.token.span;18501851        self.bump(); // `builtin`1852        self.bump(); // `#`18531854        let Some((ident, IdentKind::Normal)) = self.token.ident() else {1855            let err = self1856                .dcx()1857                .create_err(crate::diagnostics::ExpectedBuiltinIdent { span: self.token.span });1858            return Err(err);1859        };1860        self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);1861        self.bump();18621863        self.expect(exp!(OpenParen))?;1864        let ret = if let Some(res) = parse(self, lo, ident)? {1865            Ok(res)1866        } else {1867            let err = self.dcx().create_err(crate::diagnostics::UnknownBuiltinConstruct {1868                span: lo.to(ident.span),1869                name: ident,1870            });1871            return Err(err);1872        };1873        self.expect(exp!(CloseParen))?;18741875        ret1876    }18771878    /// Built-in macro for `offset_of!` expressions.1879    pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {1880        let container = self.parse_ty()?;1881        self.expect(exp!(Comma))?;18821883        let fields = self.parse_floating_field_access()?;1884        let trailing_comma = self.eat_noexpect(&TokenKind::Comma);18851886        if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {1887            if trailing_comma {1888                e.note("unexpected third argument to offset_of");1889            } else {1890                e.note("offset_of expects dot-separated field and variant names");1891            }1892            e.emit();1893        }18941895        // Eat tokens until the macro call ends.1896        if self.may_recover() {1897            while !self.token.kind.is_close_delim_or_eof() {1898                self.bump();1899            }1900        }19011902        let span = lo.to(self.token.span);1903        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))1904    }19051906    /// Built-in macro for type ascription expressions.1907    pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {1908        let expr = self.parse_expr()?;1909        self.expect(exp!(Comma))?;1910        let ty = self.parse_ty()?;1911        let span = lo.to(self.token.span);1912        Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))1913    }19141915    pub(crate) fn parse_expr_unsafe_binder_cast(1916        &mut self,1917        lo: Span,1918        kind: UnsafeBinderCastKind,1919    ) -> PResult<'a, Box<Expr>> {1920        let expr = self.parse_expr()?;1921        let ty = if self.eat(exp!(Comma)) { Some(self.parse_ty()?) } else { None };1922        let span = lo.to(self.token.span);1923        Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))1924    }19251926    /// Returns a string literal if the next token is a string literal.1927    /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,1928    /// and returns `None` if the next token is not literal at all.1929    pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {1930        match self.parse_opt_meta_item_lit() {1931            Some(lit) => match lit.kind {1932                ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {1933                    style,1934                    symbol: lit.symbol,1935                    suffix: lit.suffix,1936                    span: lit.span,1937                    symbol_unescaped,1938                }),1939                _ => Err(Some(lit)),1940            },1941            None => Err(None),1942        }1943    }19441945    pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {1946        (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)1947    }19481949    fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {1950        ast::MetaItemLit {1951            symbol: name,1952            suffix: None,1953            kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),1954            span,1955        }1956    }19571958    fn handle_missing_lit<L>(1959        &mut self,1960        mk_lit_char: impl FnOnce(Symbol, Span) -> L,1961    ) -> PResult<'a, L> {1962        let token = self.token;1963        let err = |self_: &Self| {1964            let msg = format!("unexpected token: {}", super::token_descr(&token));1965            self_.dcx().struct_span_err(token.span, msg)1966        };1967        // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that1968        // makes sense.1969        if let Some((ident, IdentKind::Normal)) = self.token.lifetime()1970            && could_be_unclosed_char_literal(ident)1971        {1972            let lt = self.expect_lifetime();1973            Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))1974        } else {1975            Err(err(self))1976        }1977    }19781979    pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {1980        self.parse_opt_token_lit()1981            .ok_or(())1982            .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))1983    }19841985    pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {1986        self.parse_opt_meta_item_lit()1987            .ok_or(())1988            .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))1989    }19901991    fn recover_after_dot(&mut self) {1992        if self.token == token::Dot {1993            // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where1994            // dot would follow an optional literal, so we do this unconditionally.1995            let recovered = self.look_ahead(1, |next_token| {1996                // If it's an integer that looks like a float, then recover as such.1997                //1998                // We will never encounter the exponent part of a floating1999                // point literal here, since there's no use of the exponent2000                // syntax that also constitutes a valid integer, so we need

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings