1// ignore-tidy-filelength23use core::mem;4use core::ops::{Bound, ControlFlow};56use 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, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param,19 RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,20};21use rustc_ast_pretty::pprust;22use rustc_data_structures::stack::ensure_sufficient_stack;23use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};24use rustc_literal_escaper::unescape_char;25use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};26use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;27use rustc_span::edition::Edition;28use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym};29use thin_vec::{ThinVec, thin_vec};30use tracing::instrument;3132use super::diagnostics::SnapshotParser;33use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};34use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};35use super::{36 AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,37 Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,38};39use crate::{errors, exp, maybe_recover_from_interpolated_ty_qpath};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();5859 let attrs = self.parse_outer_attributes()?;60 self.parse_expr_res(Restrictions::empty(), attrs).map(|res| res.0)61 }6263 /// Parses an expression, forcing tokens to be collected.64 pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {65 self.current_closure.take();6667 // If the expression is associative (e.g. `1 + 2`), then any preceding68 // outer attribute actually belongs to the first inner sub-expression.69 // In which case we must use the pre-attr pos to include the attribute70 // in the collected tokens for the outer expression.71 let pre_attr_pos = self.collect_pos();72 let attrs = self.parse_outer_attributes()?;73 self.collect_tokens(74 Some(pre_attr_pos),75 AttrWrapper::empty(),76 ForceCollect::Yes,77 |this, _empty_attrs| {78 let (expr, is_assoc) = this.parse_expr_res(Restrictions::empty(), attrs)?;79 let use_pre_attr_pos =80 if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };81 Ok((expr, Trailing::No, use_pre_attr_pos))82 },83 )84 }8586 pub fn parse_expr_anon_const(87 &mut self,88 mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation,89 ) -> PResult<'a, AnonConst> {90 self.parse_expr().map(|value| AnonConst {91 id: DUMMY_NODE_ID,92 mgca_disambiguation: mgca_disambiguation(self, &value),93 value,94 })95 }9697 fn parse_expr_catch_underscore(98 &mut self,99 restrictions: Restrictions,100 ) -> PResult<'a, Box<Expr>> {101 let attrs = self.parse_outer_attributes()?;102 match self.parse_expr_res(restrictions, attrs) {103 Ok((expr, _)) => Ok(expr),104 Err(err) => match self.token.ident() {105 Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No))106 if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>107 {108 // Special-case handling of `foo(_, _, _)`109 let guar = err.emit();110 self.bump();111 Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar)))112 }113 _ => Err(err),114 },115 }116 }117118 /// Parses a sequence of expressions delimited by parentheses.119 fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {120 self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore(Restrictions::empty()))121 .map(|(r, _)| r)122 }123124 /// Parses an expression, subject to the given restrictions.125 #[inline]126 pub(super) fn parse_expr_res(127 &mut self,128 r: Restrictions,129 attrs: AttrWrapper,130 ) -> PResult<'a, (Box<Expr>, bool)> {131 self.with_res(r, |this| this.parse_expr_assoc_with(Bound::Unbounded, attrs))132 }133134 /// Parses an associative expression with operators of at least `min_prec` precedence.135 /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator136 /// followed by a subexpression (e.g. `1 + 2`).137 pub(super) fn parse_expr_assoc_with(138 &mut self,139 min_prec: Bound<ExprPrecedence>,140 attrs: AttrWrapper,141 ) -> PResult<'a, (Box<Expr>, bool)> {142 let lhs = if self.token.is_range_separator() {143 return self.parse_expr_prefix_range(attrs).map(|res| (res, false));144 } else {145 self.parse_expr_prefix(attrs)?146 };147 self.parse_expr_assoc_rest_with(min_prec, false, lhs)148 }149150 /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators151 /// of at least `min_prec` precedence. The `bool` in the return value indicates if something152 /// was actually parsed.153 pub(super) fn parse_expr_assoc_rest_with(154 &mut self,155 min_prec: Bound<ExprPrecedence>,156 starts_stmt: bool,157 mut lhs: Box<Expr>,158 ) -> PResult<'a, (Box<Expr>, bool)> {159 let mut parsed_something = false;160 if !self.should_continue_as_assoc_expr(&lhs) {161 return Ok((lhs, parsed_something));162 }163164 self.expected_token_types.insert(TokenType::Operator);165 while let Some(op) = self.check_assoc_op() {166 let lhs_span = self.interpolated_or_expr_span(&lhs);167 let cur_op_span = self.token.span;168 let restrictions = if op.node.is_assign_like() {169 self.restrictions & Restrictions::NO_STRUCT_LITERAL170 } else {171 self.restrictions172 };173 let prec = op.node.precedence();174 if match min_prec {175 Bound::Included(min_prec) => prec < min_prec,176 Bound::Excluded(min_prec) => prec <= min_prec,177 Bound::Unbounded => false,178 } {179 break;180 }181 // Check for deprecated `...` syntax182 if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {183 self.err_dotdotdot_syntax(self.token.span);184 }185186 if self.token == token::LArrow {187 self.err_larrow_operator(self.token.span);188 }189190 parsed_something = true;191 self.bump();192 if op.node.is_comparison() {193 if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {194 return Ok((expr, parsed_something));195 }196 }197198 // Look for JS' `===` and `!==` and recover199 if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node200 && self.token == token::Eq201 && self.prev_token.span.hi() == self.token.span.lo()202 {203 let sp = op.span.to(self.token.span);204 let sugg = bop.as_str().into();205 let invalid = format!("{sugg}=");206 self.dcx().emit_err(errors::InvalidComparisonOperator {207 span: sp,208 invalid: invalid.clone(),209 sub: errors::InvalidComparisonOperatorSub::Correctable {210 span: sp,211 invalid,212 correct: sugg,213 },214 });215 self.bump();216 }217218 // Look for PHP's `<>` and recover219 if op.node == AssocOp::Binary(BinOpKind::Lt)220 && self.token == token::Gt221 && self.prev_token.span.hi() == self.token.span.lo()222 {223 let sp = op.span.to(self.token.span);224 self.dcx().emit_err(errors::InvalidComparisonOperator {225 span: sp,226 invalid: "<>".into(),227 sub: errors::InvalidComparisonOperatorSub::Correctable {228 span: sp,229 invalid: "<>".into(),230 correct: "!=".into(),231 },232 });233 self.bump();234 }235236 // Look for C++'s `<=>` and recover237 if op.node == AssocOp::Binary(BinOpKind::Le)238 && self.token == token::Gt239 && self.prev_token.span.hi() == self.token.span.lo()240 {241 let sp = op.span.to(self.token.span);242 self.dcx().emit_err(errors::InvalidComparisonOperator {243 span: sp,244 invalid: "<=>".into(),245 sub: errors::InvalidComparisonOperatorSub::Spaceship(sp),246 });247 self.bump();248 }249250 if self.prev_token == token::Plus251 && self.token == token::Plus252 && self.prev_token.span.between(self.token.span).is_empty()253 {254 let op_span = self.prev_token.span.to(self.token.span);255 // Eat the second `+`256 self.bump();257 lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;258 continue;259 }260261 if self.prev_token == token::Minus262 && self.token == token::Minus263 && self.prev_token.span.between(self.token.span).is_empty()264 && !self.look_ahead(1, |tok| tok.can_begin_expr())265 {266 let op_span = self.prev_token.span.to(self.token.span);267 // Eat the second `-`268 self.bump();269 lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?;270 continue;271 }272273 let op_span = op.span;274 let op = op.node;275 // Special cases:276 if op == AssocOp::Cast {277 lhs = self.parse_assoc_op_cast(lhs, lhs_span, op_span, ExprKind::Cast)?;278 continue;279 } else if let AssocOp::Range(limits) = op {280 // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to281 // generalise it to the Fixity::None code.282 lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;283 break;284 }285286 let min_prec = match op.fixity() {287 Fixity::Right => Bound::Included(prec),288 Fixity::Left | Fixity::None => Bound::Excluded(prec),289 };290 let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {291 let attrs = this.parse_outer_attributes()?;292 this.parse_expr_assoc_with(min_prec, attrs)293 })?;294295 let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);296 lhs = match op {297 AssocOp::Binary(ast_op) => {298 let binary = self.mk_binary(respan(cur_op_span, ast_op), lhs, rhs);299 self.mk_expr(span, binary)300 }301 AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),302 AssocOp::AssignOp(aop) => {303 let aopexpr = self.mk_assign_op(respan(cur_op_span, aop), lhs, rhs);304 self.mk_expr(span, aopexpr)305 }306 AssocOp::Cast | AssocOp::Range(_) => {307 self.dcx().span_bug(span, "AssocOp should have been handled by special case")308 }309 };310 }311312 Ok((lhs, parsed_something))313 }314315 fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {316 match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {317 // Semi-statement forms are odd:318 // See https://github.com/rust-lang/rust/issues/29071319 (true, None) => false,320 (false, _) => true, // Continue parsing the expression.321 // An exhaustive check is done in the following block, but these are checked first322 // because they *are* ambiguous but also reasonable looking incorrect syntax, so we323 // want to keep their span info to improve diagnostics in these cases in a later stage.324 (true, Some(AssocOp::Binary(325 BinOpKind::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3`326 BinOpKind::Sub | // `{ 42 } -5`327 BinOpKind::Add | // `{ 42 } + 42` (unary plus)328 BinOpKind::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`329 BinOpKind::Or | // `{ 42 } || 42` ("logical or" or closure)330 BinOpKind::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42`331 ))) => {332 // These cases are ambiguous and can't be identified in the parser alone.333 //334 // Bitwise AND is left out because guessing intent is hard. We can make335 // suggestions based on the assumption that double-refs are rarely intentional,336 // and closures are distinct enough that they don't get mixed up with their337 // return value.338 let sp = self.psess.source_map().start_point(self.token.span);339 self.psess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);340 false341 }342 (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,343 (true, Some(_)) => {344 self.error_found_expr_would_be_stmt(lhs);345 true346 }347 }348 }349350 /// We've found an expression that would be parsed as a statement,351 /// but the next token implies this should be parsed as an expression.352 /// For example: `if let Some(x) = x { x } else { 0 } / 2`.353 fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {354 self.dcx().emit_err(errors::FoundExprWouldBeStmt {355 span: self.token.span,356 token: pprust::token_to_string(&self.token),357 suggestion: ExprParenthesesNeeded::surrounding(lhs.span),358 });359 }360361 /// Possibly translate the current token to an associative operator.362 /// The method does not advance the current token.363 ///364 /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.365 pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {366 let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {367 // When parsing const expressions, stop parsing when encountering `>`.368 (369 Some(370 AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)371 | AssocOp::AssignOp(AssignOpKind::ShrAssign),372 ),373 _,374 ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {375 return None;376 }377 // When recovering patterns as expressions, stop parsing when encountering an378 // assignment `=`, an alternative `|`, or a range `..`.379 (380 Some(381 AssocOp::Assign382 | AssocOp::AssignOp(_)383 | AssocOp::Binary(BinOpKind::BitOr)384 | AssocOp::Range(_),385 ),386 _,387 ) if self.restrictions.contains(Restrictions::IS_PAT) => {388 return None;389 }390 (Some(op), _) => (op, self.token.span),391 (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No)))392 if self.may_recover() =>393 {394 self.dcx().emit_err(errors::InvalidLogicalOperator {395 span: self.token.span,396 incorrect: "and".into(),397 sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),398 });399 (AssocOp::Binary(BinOpKind::And), span)400 }401 (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {402 self.dcx().emit_err(errors::InvalidLogicalOperator {403 span: self.token.span,404 incorrect: "or".into(),405 sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),406 });407 (AssocOp::Binary(BinOpKind::Or), span)408 }409 _ => return None,410 };411 Some(respan(span, op))412 }413414 /// Checks if this expression is a successfully parsed statement.415 fn expr_is_complete(&self, e: &Expr) -> bool {416 self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)417 }418419 /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.420 /// The other two variants are handled in `parse_prefix_range_expr` below.421 fn parse_expr_range(422 &mut self,423 prec: ExprPrecedence,424 lhs: Box<Expr>,425 limits: RangeLimits,426 cur_op_span: Span,427 ) -> PResult<'a, Box<Expr>> {428 let rhs = if self.is_at_start_of_range_notation_rhs() {429 let maybe_lt = self.token;430 let attrs = self.parse_outer_attributes()?;431 Some(432 self.parse_expr_assoc_with(Bound::Excluded(prec), attrs)433 .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?434 .0,435 )436 } else {437 None438 };439 let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);440 let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);441 let range = self.mk_range(Some(lhs), rhs, limits);442 Ok(self.mk_expr(span, range))443 }444445 fn is_at_start_of_range_notation_rhs(&self) -> bool {446 if self.token.can_begin_expr() {447 // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.448 if self.token == token::OpenBrace {449 return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);450 }451 true452 } else {453 false454 }455 }456457 /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.458 fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {459 if !attrs.is_empty() {460 let err = errors::DotDotRangeAttribute { span: self.token.span };461 self.dcx().emit_err(err);462 }463464 // Check for deprecated `...` syntax.465 if self.token == token::DotDotDot {466 self.err_dotdotdot_syntax(self.token.span);467 }468469 debug_assert!(470 self.token.is_range_separator(),471 "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",472 self.token473 );474475 let limits = match self.token.kind {476 token::DotDot => RangeLimits::HalfOpen,477 _ => RangeLimits::Closed,478 };479 let op = AssocOp::from_token(&self.token);480 let attrs = self.parse_outer_attributes()?;481 self.collect_tokens_for_expr(attrs, |this, attrs| {482 let lo = this.token.span;483 let maybe_lt = this.look_ahead(1, |t| t.clone());484 this.bump();485 let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {486 // RHS must be parsed with more associativity than the dots.487 let attrs = this.parse_outer_attributes()?;488 this.parse_expr_assoc_with(Bound::Excluded(op.unwrap().precedence()), attrs)489 .map(|(x, _)| (lo.to(x.span), Some(x)))490 .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?491 } else {492 (lo, None)493 };494 let range = this.mk_range(None, opt_end, limits);495 Ok(this.mk_expr_with_attrs(span, range, attrs))496 })497 }498499 /// Parses a prefix-unary-operator expr.500 fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {501 let lo = self.token.span;502503 macro_rules! make_it {504 ($this:ident, $attrs:expr, |this, _| $body:expr) => {505 $this.collect_tokens_for_expr($attrs, |$this, attrs| {506 let (hi, ex) = $body?;507 Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))508 })509 };510 }511512 let this = self;513514 // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()515 match this.token.uninterpolate().kind {516 // `!expr`517 token::Bang => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)),518 // `~expr`519 token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),520 // `-expr`521 token::Minus => {522 make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg))523 }524 // `*expr`525 token::Star => {526 make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref))527 }528 // `&expr` and `&&expr`529 token::And | token::AndAnd => {530 make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo))531 }532 // `+lit`533 token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {534 let mut err = errors::LeadingPlusNotSupported {535 span: lo,536 remove_plus: None,537 add_parentheses: None,538 };539540 // a block on the LHS might have been intended to be an expression instead541 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {542 err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));543 } else {544 err.remove_plus = Some(lo);545 }546 this.dcx().emit_err(err);547548 this.bump();549 let attrs = this.parse_outer_attributes()?;550 this.parse_expr_prefix(attrs)551 }552 // Recover from `++x`:553 token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {554 let starts_stmt =555 this.prev_token == token::Semi || this.prev_token == token::CloseBrace;556 let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));557 // Eat both `+`s.558 this.bump();559 this.bump();560561 let operand_expr = this.parse_expr_dot_or_call(attrs)?;562 this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)563 }564 token::Ident(..) if this.token.is_keyword(kw::Box) => {565 make_it!(this, attrs, |this, _| this.parse_expr_box(lo))566 }567 token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {568 make_it!(this, attrs, |this, _| this.recover_not_expr(lo))569 }570 _ => return this.parse_expr_dot_or_call(attrs),571 }572 }573574 fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {575 self.bump();576 let attrs = self.parse_outer_attributes()?;577 let expr = if self.token.is_range_separator() {578 self.parse_expr_prefix_range(attrs)579 } else {580 self.parse_expr_prefix(attrs)581 }?;582 let span = self.interpolated_or_expr_span(&expr);583 Ok((lo.to(span), expr))584 }585586 fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {587 let (span, expr) = self.parse_expr_prefix_common(lo)?;588 Ok((span, self.mk_unary(op, expr)))589 }590591 /// Recover on `~expr` in favor of `!expr`.592 fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {593 self.dcx().emit_err(errors::TildeAsUnaryOperator(lo));594595 self.parse_expr_unary(lo, UnOp::Not)596 }597598 /// Parse `box expr` - this syntax has been removed, but we still parse this599 /// for now to provide a more useful error600 fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> {601 let (span, expr) = self.parse_expr_prefix_common(box_kw)?;602 // Make a multipart suggestion instead of `span_to_snippet` in case source isn't available603 let box_kw_and_lo = box_kw.until(self.interpolated_or_expr_span(&expr));604 let hi = span.shrink_to_hi();605 let sugg = errors::AddBoxNew { box_kw_and_lo, hi };606 let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span, sugg });607 Ok((span, ExprKind::Err(guar)))608 }609610 fn is_mistaken_not_ident_negation(&self) -> bool {611 let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {612 // These tokens can start an expression after `!`, but613 // can't continue an expression after an ident614 token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),615 token::Literal(..) | token::Pound => true,616 _ => t.is_metavar_expr(),617 };618 self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)619 }620621 /// Recover on `not expr` in favor of `!expr`.622 fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {623 let negated_token = self.look_ahead(1, |t| *t);624625 let sub_diag = if negated_token.is_numeric_lit() {626 errors::NotAsNegationOperatorSub::SuggestNotBitwise627 } else if negated_token.is_bool_lit() {628 errors::NotAsNegationOperatorSub::SuggestNotLogical629 } else {630 errors::NotAsNegationOperatorSub::SuggestNotDefault631 };632633 self.dcx().emit_err(errors::NotAsNegationOperator {634 negated: negated_token.span,635 negated_desc: super::token_descr(&negated_token),636 // Span the `not` plus trailing whitespace to avoid637 // trailing whitespace after the `!` in our suggestion638 sub: sub_diag(639 self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),640 ),641 });642643 self.parse_expr_unary(lo, UnOp::Not)644 }645646 /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.647 fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {648 match self.prev_token.kind {649 token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,650 token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {651 // `expr.span` is the interpolated span, because invisible open652 // and close delims both get marked with the same span, one653 // that covers the entire thing between them. (See654 // `rustc_expand::mbe::transcribe::transcribe`.)655 self.prev_token.span656 }657 _ => expr.span,658 }659 }660661 fn parse_assoc_op_cast(662 &mut self,663 lhs: Box<Expr>,664 lhs_span: Span,665 op_span: Span,666 expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind,667 ) -> PResult<'a, Box<Expr>> {668 let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| {669 this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))670 };671672 // Save the state of the parser before parsing type normally, in case there is a673 // LessThan comparison after this cast.674 let parser_snapshot_before_type = self.clone();675 let cast_expr = match self.parse_as_cast_ty() {676 Ok(rhs) => mk_expr(self, lhs, rhs),677 Err(type_err) => {678 if !self.may_recover() {679 return Err(type_err);680 }681682 // Rewind to before attempting to parse the type with generics, to recover683 // from situations like `x as usize < y` in which we first tried to parse684 // `usize < y` as a type with generic arguments.685 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);686687 // Check for typo of `'a: loop { break 'a }` with a missing `'`.688 match (&lhs.kind, &self.token.kind) {689 (690 // `foo: `691 ExprKind::Path(None, ast::Path { segments, .. }),692 token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),693 ) if let [segment] = segments.as_slice() => {694 let snapshot = self.create_snapshot_for_diagnostic();695 let label = Label {696 ident: Ident::from_str_and_span(697 &format!("'{}", segment.ident),698 segment.ident.span,699 ),700 };701 match self.parse_expr_labeled(label, false) {702 Ok(expr) => {703 type_err.cancel();704 self.dcx().emit_err(errors::MalformedLoopLabel {705 span: label.ident.span,706 suggestion: label.ident.span.shrink_to_lo(),707 });708 return Ok(expr);709 }710 Err(err) => {711 err.cancel();712 self.restore_snapshot(snapshot);713 }714 }715 }716 _ => {}717 }718719 match self.parse_path(PathStyle::Expr) {720 Ok(path) => {721 let span_after_type = parser_snapshot_after_type.token.span;722 let expr = mk_expr(723 self,724 lhs,725 self.mk_ty(path.span, TyKind::Path(None, path.clone())),726 );727728 let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);729 match self.token.kind {730 token::Lt => {731 self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric {732 comparison: self.token.span,733 r#type: pprust::path_to_string(&path),734 args: args_span,735 suggestion: errors::ComparisonInterpretedAsGenericSugg {736 left: expr.span.shrink_to_lo(),737 right: expr.span.shrink_to_hi(),738 },739 })740 }741 token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric {742 shift: self.token.span,743 r#type: pprust::path_to_string(&path),744 args: args_span,745 suggestion: errors::ShiftInterpretedAsGenericSugg {746 left: expr.span.shrink_to_lo(),747 right: expr.span.shrink_to_hi(),748 },749 }),750 _ => {751 // We can end up here even without `<` being the next token, for752 // example because `parse_ty_no_plus` returns `Err` on keywords,753 // but `parse_path` returns `Ok` on them due to error recovery.754 // Return original error and parser state.755 *self = parser_snapshot_after_type;756 return Err(type_err);757 }758 };759760 // Successfully parsed the type path leaving a `<` yet to parse.761 type_err.cancel();762763 // Keep `x as usize` as an expression in AST and continue parsing.764 expr765 }766 Err(path_err) => {767 // Couldn't parse as a path, return original error and parser state.768 path_err.cancel();769 *self = parser_snapshot_after_type;770 return Err(type_err);771 }772 }773 }774 };775776 // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)777 // after a cast. If one is present, emit an error then return a valid778 // parse tree; For something like `&x as T[0]` will be as if it was779 // written `((&x) as T)[0]`.780781 let span = cast_expr.span;782783 let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;784785 // Check if an illegal postfix operator has been added after the cast.786 // If the resulting expression is not a cast, it is an illegal postfix operator.787 if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {788 let msg = format!(789 "cast cannot be followed by {}",790 match with_postfix.kind {791 ExprKind::Index(..) => "indexing",792 ExprKind::Try(_) => "`?`",793 ExprKind::Field(_, _) => "a field access",794 ExprKind::MethodCall(_) => "a method call",795 ExprKind::Call(_, _) => "a function call",796 ExprKind::Await(_, _) => "`.await`",797 ExprKind::Use(_, _) => "`.use`",798 ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",799 ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",800 ExprKind::Err(_) => return Ok(with_postfix),801 _ => unreachable!(802 "did not expect {:?} as an illegal postfix operator following cast",803 with_postfix.kind804 ),805 }806 );807 let mut err = self.dcx().struct_span_err(span, msg);808809 let suggest_parens = |err: &mut Diag<'_>| {810 let suggestions = vec![811 (span.shrink_to_lo(), "(".to_string()),812 (span.shrink_to_hi(), ")".to_string()),813 ];814 err.multipart_suggestion(815 "try surrounding the expression in parentheses",816 suggestions,817 Applicability::MachineApplicable,818 );819 };820821 suggest_parens(&mut err);822823 err.emit();824 };825 Ok(with_postfix)826 }827828 /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.829 fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {830 self.expect_and()?;831 let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);832 let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.833 let (borrow_kind, mutbl) = self.parse_borrow_modifiers();834 let attrs = self.parse_outer_attributes()?;835 let expr = if self.token.is_range_separator() {836 self.parse_expr_prefix_range(attrs)837 } else {838 self.parse_expr_prefix(attrs)839 }?;840 let hi = self.interpolated_or_expr_span(&expr);841 let span = lo.to(hi);842 if let Some(lt) = lifetime {843 self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));844 }845846 // Add expected tokens if we parsed `&raw` as an expression.847 // This will make sure we see "expected `const`, `mut`", and848 // guides recovery in case we write `&raw expr`.849 if borrow_kind == ast::BorrowKind::Ref850 && mutbl == ast::Mutability::Not851 && matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw)852 {853 self.expected_token_types.insert(TokenType::KwMut);854 self.expected_token_types.insert(TokenType::KwConst);855 }856857 Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))858 }859860 fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {861 self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });862 }863864 /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.865 fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {866 if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {867 // `raw [ const | mut ]`.868 let found_raw = self.eat_keyword(exp!(Raw));869 assert!(found_raw);870 let mutability = self.parse_mut_or_const().unwrap();871 (ast::BorrowKind::Raw, mutability)872 } else {873 match self.parse_pin_and_mut() {874 // `mut?`875 (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),876 // `pin [ const | mut ]`.877 // `pin` has been gated in `self.parse_pin_and_mut()` so we don't878 // need to gate it here.879 (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),880 }881 }882 }883884 /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.885 fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {886 self.collect_tokens_for_expr(attrs, |this, attrs| {887 let base = this.parse_expr_bottom()?;888 let span = this.interpolated_or_expr_span(&base);889 this.parse_expr_dot_or_call_with(attrs, base, span)890 })891 }892893 pub(super) fn parse_expr_dot_or_call_with(894 &mut self,895 mut attrs: ast::AttrVec,896 mut e: Box<Expr>,897 lo: Span,898 ) -> PResult<'a, Box<Expr>> {899 let mut res = ensure_sufficient_stack(|| {900 loop {901 let has_question =902 if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {903 // We are using noexpect here because we don't expect a `?` directly after904 // a `return` which could be suggested otherwise.905 self.eat_noexpect(&token::Question)906 } else {907 self.eat(exp!(Question))908 };909 if has_question {910 // `expr?`911 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));912 continue;913 }914 let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {915 // We are using noexpect here because we don't expect a `.` directly after916 // a `return` which could be suggested otherwise.917 self.eat_noexpect(&token::Dot)918 } else if self.token == TokenKind::RArrow && self.may_recover() {919 // Recovery for `expr->suffix`.920 self.bump();921 let span = self.prev_token.span;922 self.dcx().emit_err(errors::ExprRArrowCall { span });923 true924 } else {925 self.eat(exp!(Dot))926 };927 if has_dot {928 // expr.f929 e = self.parse_dot_suffix_expr(lo, e)?;930 continue;931 }932 if self.expr_is_complete(&e) {933 return Ok(e);934 }935 e = match self.token.kind {936 token::OpenParen => self.parse_expr_fn_call(lo, e),937 token::OpenBracket => self.parse_expr_index(lo, e)?,938 _ => return Ok(e),939 }940 }941 });942943 // Stitch the list of outer attributes onto the return value. A little944 // bit ugly, but the best way given the current code structure.945 if !attrs.is_empty()946 && let Ok(expr) = &mut res947 {948 mem::swap(&mut expr.attrs, &mut attrs);949 expr.attrs.extend(attrs)950 }951 res952 }953954 pub(super) fn parse_dot_suffix_expr(955 &mut self,956 lo: Span,957 base: Box<Expr>,958 ) -> PResult<'a, Box<Expr>> {959 // At this point we've consumed something like `expr.` and `self.token` holds the token960 // after the dot.961 match self.token.uninterpolate().kind {962 token::Ident(..) => self.parse_dot_suffix(base, lo),963 token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {964 let ident_span = self.token.span;965 self.bump();966 Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))967 }968 token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {969 Ok(match self.break_up_float(symbol, self.token.span) {970 // 1e2971 DestructuredFloat::Single(sym, _sp) => {972 // `foo.1e2`: a single complete dot access, fully consumed. We end up with973 // the `1e2` token in `self.prev_token` and the following token in974 // `self.token`.975 let ident_span = self.token.span;976 self.bump();977 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)978 }979 // 1.980 DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {981 // `foo.1.`: a single complete dot access and the start of another.982 // We end up with the `sym` (`1`) token in `self.prev_token` and a dot in983 // `self.token`.984 assert!(suffix.is_none());985 self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);986 self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));987 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)988 }989 // 1.2 | 1.2e3990 DestructuredFloat::MiddleDot(991 sym1,992 ident1_span,993 _dot_span,994 sym2,995 ident2_span,996 ) => {997 // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with998 // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following999 // token in `self.token`.1000 let next_token2 =1001 Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);1002 self.bump_with((next_token2, self.token_spacing));1003 self.bump();1004 let base1 =1005 self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);1006 self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)1007 }1008 DestructuredFloat::Error => base,1009 })1010 }1011 _ => {1012 self.error_unexpected_after_dot();1013 Ok(base)1014 }1015 }1016 }10171018 fn error_unexpected_after_dot(&self) {1019 let actual = super::token_descr(&self.token);1020 let span = self.token.span;1021 let sm = self.psess.source_map();1022 let (span, actual) = match (&self.token.kind, self.subparser_name) {1023 (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {1024 (span.shrink_to_hi(), format!("`{}`", snippet))1025 }1026 (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {1027 // No need to report an error. This case will only occur when parsing a pasted1028 // metavariable, and we should have emitted an error when parsing the macro call in1029 // the first place. E.g. in this code:1030 // ```1031 // macro_rules! m { ($e:expr) => { $e }; }1032 //1033 // fn main() {1034 // let f = 1;1035 // m!(f.);1036 // }1037 // ```1038 // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't1039 // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`1040 // represent the invisible delimiters).1041 self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");1042 return;1043 }1044 _ => (span, actual),1045 };1046 self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });1047 }10481049 /// We need an identifier or integer, but the next token is a float.1050 /// Break the float into components to extract the identifier or integer.1051 ///1052 /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.1053 //1054 // FIXME: With current `TokenCursor` it's hard to break tokens into more than 21055 // parts unless those parts are processed immediately. `TokenCursor` should either1056 // support pushing "future tokens" (would be also helpful to `break_and_eat`), or1057 // we should break everything including floats into more basic proc-macro style1058 // tokens in the lexer (probably preferable).1059 pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {1060 #[derive(Debug)]1061 enum FloatComponent {1062 IdentLike(String),1063 Punct(char),1064 }1065 use FloatComponent::*;10661067 let float_str = float.as_str();1068 let mut components = Vec::new();1069 let mut ident_like = String::new();1070 for c in float_str.chars() {1071 if c == '_' || c.is_ascii_alphanumeric() {1072 ident_like.push(c);1073 } else if matches!(c, '.' | '+' | '-') {1074 if !ident_like.is_empty() {1075 components.push(IdentLike(mem::take(&mut ident_like)));1076 }1077 components.push(Punct(c));1078 } else {1079 panic!("unexpected character in a float token: {c:?}")1080 }1081 }1082 if !ident_like.is_empty() {1083 components.push(IdentLike(ident_like));1084 }10851086 // With proc macros the span can refer to anything, the source may be too short,1087 // or too long, or non-ASCII. It only makes sense to break our span into components1088 // if its underlying text is identical to our float literal.1089 let can_take_span_apart =1090 || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();10911092 match &*components {1093 // 1e21094 [IdentLike(i)] => {1095 DestructuredFloat::Single(Symbol::intern(i), span)1096 }1097 // 1.1098 [IdentLike(left), Punct('.')] => {1099 let (left_span, dot_span) = if can_take_span_apart() {1100 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));1101 let dot_span = span.with_lo(left_span.hi());1102 (left_span, dot_span)1103 } else {1104 (span, span)1105 };1106 let left = Symbol::intern(left);1107 DestructuredFloat::TrailingDot(left, left_span, dot_span)1108 }1109 // 1.2 | 1.2e31110 [IdentLike(left), Punct('.'), IdentLike(right)] => {1111 let (left_span, dot_span, right_span) = if can_take_span_apart() {1112 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));1113 let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));1114 let right_span = span.with_lo(dot_span.hi());1115 (left_span, dot_span, right_span)1116 } else {1117 (span, span, span)1118 };1119 let left = Symbol::intern(left);1120 let right = Symbol::intern(right);1121 DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)1122 }1123 // 1e+ | 1e- (recovered)1124 [IdentLike(_), Punct('+' | '-')] |1125 // 1e+2 | 1e-21126 [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |1127 // 1.2e+ | 1.2e-1128 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |1129 // 1.2e+3 | 1.2e-31130 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {1131 // See the FIXME about `TokenCursor` above.1132 self.error_unexpected_after_dot();1133 DestructuredFloat::Error1134 }1135 _ => panic!("unexpected components in a float token: {components:?}"),1136 }1137 }11381139 /// Parse the field access used in offset_of, matched by `$(e:expr)+`.1140 /// Currently returns a list of idents. However, it should be possible in1141 /// future to also do array indices, which might be arbitrary expressions.1142 pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {1143 let mut fields = Vec::new();1144 let mut trailing_dot = None;11451146 loop {1147 // This is expected to use a metavariable $(args:expr)+, but the builtin syntax1148 // could be called directly. Calling `parse_expr` allows this function to only1149 // consider `Expr`s.1150 let expr = self.parse_expr()?;1151 let mut current = &expr;1152 let start_idx = fields.len();1153 loop {1154 match current.kind {1155 ExprKind::Field(ref left, right) => {1156 // Field access is read right-to-left.1157 fields.insert(start_idx, right);1158 trailing_dot = None;1159 current = left;1160 }1161 // Parse this both to give helpful error messages and to1162 // verify it can be done with this parser setup.1163 ExprKind::Index(ref left, ref _right, span) => {1164 self.dcx().emit_err(errors::ArrayIndexInOffsetOf(span));1165 current = left;1166 }1167 ExprKind::Lit(token::Lit {1168 kind: token::Float | token::Integer,1169 symbol,1170 suffix,1171 }) => {1172 if let Some(suffix) = suffix {1173 self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {1174 span: current.span,1175 suffix,1176 });1177 }1178 match self.break_up_float(symbol, current.span) {1179 // 1e21180 DestructuredFloat::Single(sym, sp) => {1181 trailing_dot = None;1182 fields.insert(start_idx, Ident::new(sym, sp));1183 }1184 // 1.1185 DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {1186 assert!(suffix.is_none());1187 trailing_dot = Some(dot_span);1188 fields.insert(start_idx, Ident::new(sym, sym_span));1189 }1190 // 1.2 | 1.2e31191 DestructuredFloat::MiddleDot(1192 symbol1,1193 span1,1194 _dot_span,1195 symbol2,1196 span2,1197 ) => {1198 trailing_dot = None;1199 fields.insert(start_idx, Ident::new(symbol2, span2));1200 fields.insert(start_idx, Ident::new(symbol1, span1));1201 }1202 DestructuredFloat::Error => {1203 trailing_dot = None;1204 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));1205 }1206 }1207 break;1208 }1209 ExprKind::Path(None, Path { ref segments, .. }) => {1210 match &segments[..] {1211 [PathSegment { ident, args: None, .. }] => {1212 trailing_dot = None;1213 fields.insert(start_idx, *ident)1214 }1215 _ => {1216 self.dcx().emit_err(errors::InvalidOffsetOf(current.span));1217 break;1218 }1219 }1220 break;1221 }1222 _ => {1223 self.dcx().emit_err(errors::InvalidOffsetOf(current.span));1224 break;1225 }1226 }1227 }12281229 if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {1230 break;1231 } else if trailing_dot.is_none() {1232 // This loop should only repeat if there is a trailing dot.1233 self.dcx().emit_err(errors::InvalidOffsetOf(self.token.span));1234 break;1235 }1236 }1237 if let Some(dot) = trailing_dot {1238 self.dcx().emit_err(errors::InvalidOffsetOf(dot));1239 }1240 Ok(fields.into_iter().collect())1241 }12421243 fn mk_expr_tuple_field_access(1244 &self,1245 lo: Span,1246 ident_span: Span,1247 base: Box<Expr>,1248 field: Symbol,1249 suffix: Option<Symbol>,1250 ) -> Box<Expr> {1251 if let Some(suffix) = suffix {1252 self.dcx()1253 .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix });1254 }1255 self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))1256 }12571258 /// Parse a function call expression, `expr(...)`.1259 fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {1260 let snapshot = if self.token == token::OpenParen {1261 Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))1262 } else {1263 None1264 };1265 let open_paren = self.token.span;12661267 let seq = self1268 .parse_expr_paren_seq()1269 .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));1270 match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {1271 Ok(expr) => expr,1272 Err(err) => self.recover_seq_parse_error(exp!(OpenParen), exp!(CloseParen), lo, err),1273 }1274 }12751276 /// If we encounter a parser state that looks like the user has written a `struct` literal with1277 /// parentheses instead of braces, recover the parser state and provide suggestions.1278 #[instrument(skip(self, seq, snapshot), level = "trace")]1279 fn maybe_recover_struct_lit_bad_delims(1280 &mut self,1281 lo: Span,1282 open_paren: Span,1283 seq: PResult<'a, Box<Expr>>,1284 snapshot: Option<(SnapshotParser<'a>, ExprKind)>,1285 ) -> PResult<'a, Box<Expr>> {1286 match (self.may_recover(), seq, snapshot) {1287 (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {1288 snapshot.bump(); // `(`1289 match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {1290 Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {1291 // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest1292 // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.1293 self.restore_snapshot(snapshot);1294 let close_paren = self.prev_token.span;1295 let span = lo.to(close_paren);1296 // filter shorthand fields1297 let fields: Vec<_> =1298 fields.into_iter().filter(|field| !field.is_shorthand).collect();12991300 let guar = if !fields.is_empty() &&1301 // `token.kind` should not be compared here.1302 // This is because the `snapshot.token.kind` is treated as the same as1303 // that of the open delim in `TokenTreesReader::parse_token_tree`, even1304 // if they are different.1305 self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")1306 {1307 err.cancel();1308 let type_str = pprust::path_to_string(&path);1309 self.dcx()1310 .create_err(errors::ParenthesesWithStructFields {1311 span,1312 braces_for_struct: errors::BracesForStructLiteral {1313 first: open_paren,1314 second: close_paren,1315 r#type: type_str.clone(),1316 },1317 no_fields_for_fn: errors::NoFieldsForFnCall {1318 r#type: type_str,1319 fields: fields1320 .into_iter()1321 .map(|field| field.span.until(field.expr.span))1322 .collect(),1323 },1324 })1325 .emit()1326 } else {1327 err.emit()1328 };1329 Ok(self.mk_expr_err(span, guar))1330 }1331 Ok(_) => Err(err),1332 Err(err2) => {1333 err2.cancel();1334 Err(err)1335 }1336 }1337 }1338 (_, seq, _) => seq,1339 }1340 }13411342 /// Parse an indexing expression `expr[...]`.1343 fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {1344 let prev_span = self.prev_token.span;1345 let open_delim_span = self.token.span;1346 self.bump(); // `[`1347 let index = self.parse_expr()?;1348 self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;1349 self.expect(exp!(CloseBracket))?;1350 Ok(self.mk_expr(1351 lo.to(self.prev_token.span),1352 self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),1353 ))1354 }13551356 /// Assuming we have just parsed `.`, continue parsing into an expression.1357 fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {1358 if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) {1359 return Ok(self.mk_await_expr(self_arg, lo));1360 }13611362 if self.eat_keyword(exp!(Use)) {1363 let use_span = self.prev_token.span;1364 self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);1365 return Ok(self.mk_use_expr(self_arg, lo));1366 }13671368 // Post-fix match1369 if self.eat_keyword(exp!(Match)) {1370 let match_span = self.prev_token.span;1371 self.psess.gated_spans.gate(sym::postfix_match, match_span);1372 return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);1373 }13741375 // Parse a postfix `yield`.1376 if self.eat_keyword(exp!(Yield)) {1377 let yield_span = self.prev_token.span;1378 self.psess.gated_spans.gate(sym::yield_expr, yield_span);1379 return Ok(1380 self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))1381 );1382 }13831384 let fn_span_lo = self.token.span;1385 let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;1386 self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);1387 self.check_turbofish_missing_angle_brackets(&mut seg);13881389 if self.check(exp!(OpenParen)) {1390 // Method call `expr.f()`1391 let args = self.parse_expr_paren_seq()?;1392 let fn_span = fn_span_lo.to(self.prev_token.span);1393 let span = lo.to(self.prev_token.span);1394 Ok(self.mk_expr(1395 span,1396 ExprKind::MethodCall(Box::new(ast::MethodCall {1397 seg,1398 receiver: self_arg,1399 args,1400 span: fn_span,1401 })),1402 ))1403 } else {1404 // Field access `expr.f`1405 let span = lo.to(self.prev_token.span);1406 if let Some(args) = seg.args {1407 // See `StashKey::GenericInFieldExpr` for more info on why we stash this.1408 self.dcx()1409 .create_err(errors::FieldExpressionWithGeneric(args.span()))1410 .stash(seg.ident.span, StashKey::GenericInFieldExpr);1411 }14121413 Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))1414 }1415 }14161417 /// At the bottom (top?) of the precedence hierarchy,1418 /// Parses things like parenthesized exprs, macros, `return`, etc.1419 ///1420 /// N.B., this does not parse outer attributes, and is private because it only works1421 /// correctly if called from `parse_expr_dot_or_call`.1422 fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {1423 maybe_recover_from_interpolated_ty_qpath!(self, true);14241425 let span = self.token.span;1426 if let Some(expr) = self.eat_metavar_seq_with_matcher(1427 |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),1428 |this| {1429 // Force collection (as opposed to just `parse_expr`) is required to avoid the1430 // attribute duplication seen in #138478.1431 let expr = this.parse_expr_force_collect();1432 // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly1433 // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line1434 // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in1435 // `compiler/rustc_index/src/bit_set/tests.rs`.1436 if this.token.kind == token::Comma {1437 this.bump();1438 }1439 expr1440 },1441 ) {1442 return Ok(expr);1443 } else if let Some(lit) =1444 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())1445 {1446 return Ok(lit);1447 } else if let Some(block) =1448 self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())1449 {1450 return Ok(self.mk_expr(span, ExprKind::Block(block, None)));1451 } else if let Some(path) =1452 self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))1453 {1454 return Ok(self.mk_expr(span, ExprKind::Path(None, path)));1455 }14561457 // Outer attributes are already parsed and will be1458 // added to the return value after the fact.14591460 let restrictions = self.restrictions;1461 self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {1462 // Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.1463 let lo = this.token.span;1464 if let token::Literal(_) = this.token.kind {1465 // This match arm is a special-case of the `_` match arm below and1466 // could be removed without changing functionality, but it's faster1467 // to have it here, especially for programs with large constants.1468 this.parse_expr_lit()1469 } else if this.check(exp!(OpenParen)) {1470 this.parse_expr_tuple_parens(restrictions)1471 } else if this.check(exp!(OpenBrace)) {1472 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {1473 return Ok(expr);1474 }1475 this.parse_expr_block(None, lo, BlockCheckMode::Default)1476 } else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {1477 this.parse_expr_closure().map_err(|mut err| {1478 // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`1479 // then suggest parens around the lhs.1480 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {1481 err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));1482 }1483 err1484 })1485 } else if this.check(exp!(OpenBracket)) {1486 this.parse_expr_array_or_repeat(exp!(CloseBracket))1487 } else if this.is_builtin() {1488 this.parse_expr_builtin()1489 } else if this.check_path() {1490 this.parse_expr_path_start()1491 } else if this.check_keyword(exp!(Move))1492 || this.check_keyword(exp!(Use))1493 || this.check_keyword(exp!(Static))1494 || this.check_const_closure()1495 {1496 this.parse_expr_closure()1497 } else if this.eat_keyword(exp!(If)) {1498 this.parse_expr_if()1499 } else if this.check_keyword(exp!(For)) {1500 if this.choose_generics_over_qpath(1) {1501 this.parse_expr_closure()1502 } else {1503 assert!(this.eat_keyword(exp!(For)));1504 this.parse_expr_for(None, lo)1505 }1506 } else if this.eat_keyword(exp!(While)) {1507 this.parse_expr_while(None, lo)1508 } else if let Some(label) = this.eat_label() {1509 this.parse_expr_labeled(label, true)1510 } else if this.eat_keyword(exp!(Loop)) {1511 this.parse_expr_loop(None, lo).map_err(|mut err| {1512 err.span_label(lo, "while parsing this `loop` expression");1513 err1514 })1515 } else if this.eat_keyword(exp!(Match)) {1516 this.parse_expr_match().map_err(|mut err| {1517 err.span_label(lo, "while parsing this `match` expression");1518 err1519 })1520 } else if this.eat_keyword(exp!(Unsafe)) {1521 this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(1522 |mut err| {1523 err.span_label(lo, "while parsing this `unsafe` expression");1524 err1525 },1526 )1527 } else if this.check_inline_const(0) {1528 this.parse_const_block(lo, false)1529 } else if this.may_recover() && this.is_do_catch_block() {1530 this.recover_do_catch()1531 } else if this.is_try_block() {1532 this.expect_keyword(exp!(Try))?;1533 this.parse_try_block(lo)1534 } else if this.eat_keyword(exp!(Return)) {1535 this.parse_expr_return()1536 } else if this.eat_keyword(exp!(Continue)) {1537 this.parse_expr_continue(lo)1538 } else if this.eat_keyword(exp!(Break)) {1539 this.parse_expr_break()1540 } else if this.eat_keyword(exp!(Yield)) {1541 this.parse_expr_yield()1542 } else if this.is_do_yeet() {1543 this.parse_expr_yeet()1544 } else if this.eat_keyword(exp!(Become)) {1545 this.parse_expr_become()1546 } else if this.check_keyword(exp!(Let)) {1547 this.parse_expr_let(restrictions)1548 } else if this.eat_keyword(exp!(Underscore)) {1549 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {1550 return Ok(expr);1551 }1552 Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))1553 } else if this.token_uninterpolated_span().at_least_rust_2018() {1554 // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.1555 let at_async = this.check_keyword(exp!(Async));1556 // check for `gen {}` and `gen move {}`1557 // or `async gen {}` and `async gen move {}`1558 // FIXME: (async) gen closures aren't yet parsed.1559 // FIXME(gen_blocks): Parse `gen async` and suggest swap1560 if this.token_uninterpolated_span().at_least_rust_2024()1561 && this.is_gen_block(kw::Gen, at_async as usize)1562 {1563 this.parse_gen_block()1564 // Check for `async {` and `async move {`,1565 } else if this.is_gen_block(kw::Async, 0) {1566 this.parse_gen_block()1567 } else if at_async {1568 this.parse_expr_closure()1569 } else if this.eat_keyword_noexpect(kw::Await) {1570 this.recover_incorrect_await_syntax(lo)1571 } else {1572 this.parse_expr_lit()1573 }1574 } else {1575 this.parse_expr_lit()1576 }1577 })1578 }15791580 fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {1581 let lo = self.token.span;1582 match self.parse_opt_token_lit() {1583 Some((token_lit, _)) => {1584 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));1585 self.maybe_recover_from_bad_qpath(expr)1586 }1587 None => self.try_macro_suggestion(),1588 }1589 }15901591 fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {1592 let lo = self.token.span;1593 self.expect(exp!(OpenParen))?;1594 let (es, trailing_comma) = match self.parse_seq_to_end(1595 exp!(CloseParen),1596 SeqSep::trailing_allowed(exp!(Comma)),1597 |p| p.parse_expr_catch_underscore(restrictions.intersection(Restrictions::ALLOW_LET)),1598 ) {1599 Ok(x) => x,1600 Err(err) => {1601 return Ok(self.recover_seq_parse_error(1602 exp!(OpenParen),1603 exp!(CloseParen),1604 lo,1605 err,1606 ));1607 }1608 };1609 let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) {1610 // `(e)` is parenthesized `e`.1611 ExprKind::Paren(es.into_iter().next().unwrap())1612 } else {1613 // `(e,)` is a tuple with only one field, `e`.1614 ExprKind::Tup(es)1615 };1616 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1617 self.maybe_recover_from_bad_qpath(expr)1618 }16191620 fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {1621 let lo = self.token.span;1622 self.bump(); // `[` or other open delim16231624 let kind = if self.eat(close) {1625 // Empty vector1626 ExprKind::Array(ThinVec::new())1627 } else {1628 // Non-empty vector1629 let first_expr = self.parse_expr()?;1630 if self.eat(exp!(Semi)) {1631 // Repeating array syntax: `[ 0; 512 ]`1632 let count = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?;1633 self.expect(close)?;1634 ExprKind::Repeat(first_expr, count)1635 } else if self.eat(exp!(Comma)) {1636 // Vector with two or more elements.1637 let sep = SeqSep::trailing_allowed(exp!(Comma));1638 let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;1639 exprs.insert(0, first_expr);1640 ExprKind::Array(exprs)1641 } else {1642 // Vector with one element1643 self.expect(close)?;1644 ExprKind::Array(thin_vec![first_expr])1645 }1646 };1647 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1648 self.maybe_recover_from_bad_qpath(expr)1649 }16501651 fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {1652 let maybe_eq_tok = self.prev_token;1653 let (qself, path) = if self.eat_lt() {1654 let lt_span = self.prev_token.span;1655 let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {1656 // Suggests using '<=' if there is an error parsing qpath when the previous token1657 // is an '=' token. Only emits suggestion if the '<' token and '=' token are1658 // directly adjacent (i.e. '=<')1659 if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {1660 let eq_lt = maybe_eq_tok.span.to(lt_span);1661 err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);1662 }1663 err1664 })?;1665 (Some(qself), path)1666 } else {1667 (None, self.parse_path(PathStyle::Expr)?)1668 };16691670 // `!`, as an operator, is prefix, so we know this isn't that.1671 let (span, kind) = if self.eat(exp!(Bang)) {1672 // MACRO INVOCATION expression1673 if qself.is_some() {1674 self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span));1675 }1676 let lo = path.span;1677 let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });1678 (lo.to(self.prev_token.span), ExprKind::MacCall(mac))1679 } else if self.check(exp!(OpenBrace))1680 && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)1681 {1682 if qself.is_some() {1683 self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);1684 }1685 return expr;1686 } else {1687 (path.span, ExprKind::Path(qself, path))1688 };16891690 let expr = self.mk_expr(span, kind);1691 self.maybe_recover_from_bad_qpath(expr)1692 }16931694 /// Parse `'label: $expr`. The label is already parsed.1695 pub(super) fn parse_expr_labeled(1696 &mut self,1697 label_: Label,1698 mut consume_colon: bool,1699 ) -> PResult<'a, Box<Expr>> {1700 let lo = label_.ident.span;1701 let label = Some(label_);1702 let ate_colon = self.eat(exp!(Colon));1703 let tok_sp = self.token.span;1704 let expr = if self.eat_keyword(exp!(While)) {1705 self.parse_expr_while(label, lo)1706 } else if self.eat_keyword(exp!(For)) {1707 self.parse_expr_for(label, lo)1708 } else if self.eat_keyword(exp!(Loop)) {1709 self.parse_expr_loop(label, lo)1710 } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {1711 self.parse_expr_block(label, lo, BlockCheckMode::Default)1712 } else if !ate_colon1713 && self.may_recover()1714 && (self.token.kind.close_delim().is_some() || self.token.is_punct())1715 && could_be_unclosed_char_literal(label_.ident)1716 {1717 let (lit, _) =1718 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {1719 self_.dcx().create_err(errors::UnexpectedTokenAfterLabel {1720 span: self_.token.span,1721 remove_label: None,1722 enclose_in_block: None,1723 })1724 });1725 consume_colon = false;1726 Ok(self.mk_expr(lo, ExprKind::Lit(lit)))1727 } else if !ate_colon1728 && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))1729 {1730 // We're probably inside of a `Path<'a>` that needs a turbofish1731 let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {1732 span: self.token.span,1733 remove_label: None,1734 enclose_in_block: None,1735 });1736 consume_colon = false;1737 Ok(self.mk_expr_err(lo, guar))1738 } else {1739 let mut err = errors::UnexpectedTokenAfterLabel {1740 span: self.token.span,1741 remove_label: None,1742 enclose_in_block: None,1743 };17441745 // Continue as an expression in an effort to recover on `'label: non_block_expr`.1746 let expr = self.parse_expr().map(|expr| {1747 let span = expr.span;17481749 let found_labeled_breaks = {1750 struct FindLabeledBreaksVisitor;17511752 impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {1753 type Result = ControlFlow<()>;1754 fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {1755 if let ExprKind::Break(Some(_label), _) = ex.kind {1756 ControlFlow::Break(())1757 } else {1758 walk_expr(self, ex)1759 }1760 }1761 }17621763 FindLabeledBreaksVisitor.visit_expr(&expr).is_break()1764 };17651766 // Suggestion involves adding a labeled block.1767 //1768 // If there are no breaks that may use this label, suggest removing the label and1769 // recover to the unmodified expression.1770 if !found_labeled_breaks {1771 err.remove_label = Some(lo.until(span));17721773 return expr;1774 }17751776 err.enclose_in_block = Some(errors::UnexpectedTokenAfterLabelSugg {1777 left: span.shrink_to_lo(),1778 right: span.shrink_to_hi(),1779 });17801781 // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.1782 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));1783 let blk = self.mk_block(thin_vec![stmt], BlockCheckMode::Default, span);1784 self.mk_expr(span, ExprKind::Block(blk, label))1785 });17861787 self.dcx().emit_err(err);1788 expr1789 }?;17901791 if !ate_colon && consume_colon {1792 self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {1793 span: expr.span,1794 label: lo,1795 label_end: lo.between(tok_sp),1796 });1797 }17981799 Ok(expr)1800 }18011802 /// Emit an error when a char is parsed as a lifetime or label because of a missing quote.1803 pub(super) fn recover_unclosed_char<L>(1804 &self,1805 ident: Ident,1806 mk_lit_char: impl FnOnce(Symbol, Span) -> L,1807 err: impl FnOnce(&Self) -> Diag<'a>,1808 ) -> L {1809 assert!(could_be_unclosed_char_literal(ident));1810 self.dcx()1811 .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {1812 err.span_suggestion_verbose(1813 ident.span.shrink_to_hi(),1814 "add `'` to close the char literal",1815 "'",1816 Applicability::MaybeIncorrect,1817 );1818 })1819 .unwrap_or_else(|| {1820 err(self)1821 .with_span_suggestion_verbose(1822 ident.span.shrink_to_hi(),1823 "add `'` to close the char literal",1824 "'",1825 Applicability::MaybeIncorrect,1826 )1827 .emit()1828 });1829 let name = ident.without_first_quote().name;1830 mk_lit_char(name, ident.span)1831 }18321833 /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.1834 fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {1835 let lo = self.token.span;18361837 self.bump(); // `do`1838 self.bump(); // `catch`18391840 let span = lo.to(self.prev_token.span);1841 self.dcx().emit_err(errors::DoCatchSyntaxRemoved { span });18421843 self.parse_try_block(lo)1844 }18451846 /// Parse an expression if the token can begin one.1847 fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {1848 Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })1849 }18501851 /// Parse `"return" expr?`.1852 fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {1853 let lo = self.prev_token.span;1854 let kind = ExprKind::Ret(self.parse_expr_opt()?);1855 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1856 self.maybe_recover_from_bad_qpath(expr)1857 }18581859 /// Parse `"do" "yeet" expr?`.1860 fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {1861 let lo = self.token.span;18621863 self.bump(); // `do`1864 self.bump(); // `yeet`18651866 let kind = ExprKind::Yeet(self.parse_expr_opt()?);18671868 let span = lo.to(self.prev_token.span);1869 self.psess.gated_spans.gate(sym::yeet_expr, span);1870 let expr = self.mk_expr(span, kind);1871 self.maybe_recover_from_bad_qpath(expr)1872 }18731874 /// Parse `"become" expr`, with `"become"` token already eaten.1875 fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {1876 let lo = self.prev_token.span;1877 let kind = ExprKind::Become(self.parse_expr()?);1878 let span = lo.to(self.prev_token.span);1879 self.psess.gated_spans.gate(sym::explicit_tail_calls, span);1880 let expr = self.mk_expr(span, kind);1881 self.maybe_recover_from_bad_qpath(expr)1882 }18831884 /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.1885 /// If the label is followed immediately by a `:` token, the label and `:` are1886 /// parsed as part of the expression (i.e. a labeled loop). The language team has1887 /// decided in #87026 to require parentheses as a visual aid to avoid confusion if1888 /// the break expression of an unlabeled break is a labeled loop (as in1889 /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value1890 /// expression only gets a warning for compatibility reasons; and a labeled break1891 /// with a labeled loop does not even get a warning because there is no ambiguity.1892 fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {1893 let lo = self.prev_token.span;1894 let mut label = self.eat_label();1895 let kind = if self.token == token::Colon1896 && let Some(label) = label.take()1897 {1898 // The value expression can be a labeled loop, see issue #86948, e.g.:1899 // `loop { break 'label: loop { break 'label 42; }; }`1900 let lexpr = self.parse_expr_labeled(label, true)?;1901 self.dcx().emit_err(errors::LabeledLoopInBreak {1902 span: lexpr.span,1903 sub: errors::WrapInParentheses::Expression {1904 left: lexpr.span.shrink_to_lo(),1905 right: lexpr.span.shrink_to_hi(),1906 },1907 });1908 Some(lexpr)1909 } else if self.token != token::OpenBrace1910 || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)1911 {1912 let mut expr = self.parse_expr_opt()?;1913 if let Some(expr) = &mut expr {1914 if label.is_some()1915 && match &expr.kind {1916 ExprKind::While(_, _, None)1917 | ExprKind::ForLoop { label: None, .. }1918 | ExprKind::Loop(_, None, _) => true,1919 ExprKind::Block(block, None) => {1920 matches!(block.rules, BlockCheckMode::Default)1921 }1922 _ => false,1923 }1924 {1925 let span = expr.span;1926 self.psess.buffer_lint(1927 BREAK_WITH_LABEL_AND_LOOP,1928 lo.to(expr.span),1929 ast::CRATE_NODE_ID,1930 errors::BreakWithLabelAndLoop {1931 sub: errors::BreakWithLabelAndLoopSub {1932 left: span.shrink_to_lo(),1933 right: span.shrink_to_hi(),1934 },1935 },1936 );1937 }19381939 // Recover `break label aaaaa`1940 if self.may_recover()1941 && let ExprKind::Path(None, p) = &expr.kind1942 && let [segment] = &*p.segments1943 && let &ast::PathSegment { ident, args: None, .. } = segment1944 && let Some(next) = self.parse_expr_opt()?1945 {1946 label = Some(self.recover_ident_into_label(ident));1947 *expr = next;1948 }1949 }19501951 expr1952 } else {1953 None1954 };1955 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));1956 self.maybe_recover_from_bad_qpath(expr)1957 }19581959 /// Parse `"continue" label?`.1960 fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {1961 let mut label = self.eat_label();19621963 // Recover `continue label` -> `continue 'label`1964 if self.may_recover()1965 && label.is_none()1966 && let Some((ident, _)) = self.token.ident()1967 {1968 self.bump();1969 label = Some(self.recover_ident_into_label(ident));1970 }19711972 let kind = ExprKind::Continue(label);1973 Ok(self.mk_expr(lo.to(self.prev_token.span), kind))1974 }19751976 /// Parse `"yield" expr?`.1977 fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {1978 let lo = self.prev_token.span;1979 let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));1980 let span = lo.to(self.prev_token.span);1981 self.psess.gated_spans.gate(sym::yield_expr, span);1982 let expr = self.mk_expr(span, kind);1983 self.maybe_recover_from_bad_qpath(expr)1984 }19851986 /// Parse `builtin # ident(args,*)`.1987 fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> {1988 self.parse_builtin(|this, lo, ident| {1989 Ok(match ident.name {1990 sym::offset_of => Some(this.parse_expr_offset_of(lo)?),1991 sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),1992 sym::wrap_binder => {1993 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)1994 }1995 sym::unwrap_binder => {1996 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)1997 }1998 _ => None,1999 })2000 })
Findings
✓ No findings reported for this file.