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(..)568 if this.token.is_keyword(kw::Move)569 && this.look_ahead(1, |t| *t == token::OpenParen) =>570 {571 make_it!(this, attrs, |this, _| this.parse_expr_move(lo))572 }573 token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {574 make_it!(this, attrs, |this, _| this.recover_not_expr(lo))575 }576 _ => return this.parse_expr_dot_or_call(attrs),577 }578 }579580 fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {581 self.bump();582 let attrs = self.parse_outer_attributes()?;583 let expr = if self.token.is_range_separator() {584 self.parse_expr_prefix_range(attrs)585 } else {586 self.parse_expr_prefix(attrs)587 }?;588 let span = self.interpolated_or_expr_span(&expr);589 Ok((lo.to(span), expr))590 }591592 fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {593 let (span, expr) = self.parse_expr_prefix_common(lo)?;594 Ok((span, self.mk_unary(op, expr)))595 }596597 /// Recover on `~expr` in favor of `!expr`.598 fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {599 self.dcx().emit_err(errors::TildeAsUnaryOperator(lo));600601 self.parse_expr_unary(lo, UnOp::Not)602 }603604 /// Parse `box expr` - this syntax has been removed, but we still parse this605 /// for now to provide a more useful error606 fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> {607 let (span, expr) = self.parse_expr_prefix_common(box_kw)?;608 // Make a multipart suggestion instead of `span_to_snippet` in case source isn't available609 let box_kw_and_lo = box_kw.until(self.interpolated_or_expr_span(&expr));610 let hi = span.shrink_to_hi();611 let sugg = errors::AddBoxNew { box_kw_and_lo, hi };612 let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span, sugg });613 Ok((span, ExprKind::Err(guar)))614 }615616 fn parse_expr_move(&mut self, move_kw: Span) -> PResult<'a, (Span, ExprKind)> {617 self.bump();618 self.psess.gated_spans.gate(sym::move_expr, move_kw);619 self.expect(exp!(OpenParen))?;620 let expr = self.parse_expr()?;621 self.expect(exp!(CloseParen))?;622 let span = move_kw.to(self.prev_token.span);623 Ok((span, ExprKind::Move(expr, move_kw)))624 }625626 fn is_mistaken_not_ident_negation(&self) -> bool {627 let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {628 // These tokens can start an expression after `!`, but629 // can't continue an expression after an ident630 token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),631 token::Literal(..) | token::Pound => true,632 _ => t.is_metavar_expr(),633 };634 self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)635 }636637 /// Recover on `not expr` in favor of `!expr`.638 fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {639 let negated_token = self.look_ahead(1, |t| *t);640641 let sub_diag = if negated_token.is_numeric_lit() {642 errors::NotAsNegationOperatorSub::SuggestNotBitwise643 } else if negated_token.is_bool_lit() {644 errors::NotAsNegationOperatorSub::SuggestNotLogical645 } else {646 errors::NotAsNegationOperatorSub::SuggestNotDefault647 };648649 self.dcx().emit_err(errors::NotAsNegationOperator {650 negated: negated_token.span,651 negated_desc: super::token_descr(&negated_token),652 // Span the `not` plus trailing whitespace to avoid653 // trailing whitespace after the `!` in our suggestion654 sub: sub_diag(655 self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),656 ),657 });658659 self.parse_expr_unary(lo, UnOp::Not)660 }661662 /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.663 fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {664 match self.prev_token.kind {665 token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,666 token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {667 // `expr.span` is the interpolated span, because invisible open668 // and close delims both get marked with the same span, one669 // that covers the entire thing between them. (See670 // `rustc_expand::mbe::transcribe::transcribe`.)671 self.prev_token.span672 }673 _ => expr.span,674 }675 }676677 fn parse_assoc_op_cast(678 &mut self,679 lhs: Box<Expr>,680 lhs_span: Span,681 op_span: Span,682 expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind,683 ) -> PResult<'a, Box<Expr>> {684 let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| {685 this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))686 };687688 // Save the state of the parser before parsing type normally, in case there is a689 // LessThan comparison after this cast.690 let parser_snapshot_before_type = self.clone();691 let cast_expr = match self.parse_as_cast_ty() {692 Ok(rhs) => mk_expr(self, lhs, rhs),693 Err(type_err) => {694 if !self.may_recover() {695 return Err(type_err);696 }697698 // Rewind to before attempting to parse the type with generics, to recover699 // from situations like `x as usize < y` in which we first tried to parse700 // `usize < y` as a type with generic arguments.701 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);702703 // Check for typo of `'a: loop { break 'a }` with a missing `'`.704 match (&lhs.kind, &self.token.kind) {705 (706 // `foo: `707 ExprKind::Path(None, ast::Path { segments, .. }),708 token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),709 ) if let [segment] = segments.as_slice() => {710 let snapshot = self.create_snapshot_for_diagnostic();711 let label = Label {712 ident: Ident::from_str_and_span(713 &format!("'{}", segment.ident),714 segment.ident.span,715 ),716 };717 match self.parse_expr_labeled(label, false) {718 Ok(expr) => {719 type_err.cancel();720 self.dcx().emit_err(errors::MalformedLoopLabel {721 span: label.ident.span,722 suggestion: label.ident.span.shrink_to_lo(),723 });724 return Ok(expr);725 }726 Err(err) => {727 err.cancel();728 self.restore_snapshot(snapshot);729 }730 }731 }732 _ => {}733 }734735 match self.parse_path(PathStyle::Expr) {736 Ok(path) => {737 let span_after_type = parser_snapshot_after_type.token.span;738 let expr = mk_expr(739 self,740 lhs,741 self.mk_ty(path.span, TyKind::Path(None, path.clone())),742 );743744 let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);745 match self.token.kind {746 token::Lt => {747 self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric {748 comparison: self.token.span,749 r#type: pprust::path_to_string(&path),750 args: args_span,751 suggestion: errors::ComparisonInterpretedAsGenericSugg {752 left: expr.span.shrink_to_lo(),753 right: expr.span.shrink_to_hi(),754 },755 })756 }757 token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric {758 shift: self.token.span,759 r#type: pprust::path_to_string(&path),760 args: args_span,761 suggestion: errors::ShiftInterpretedAsGenericSugg {762 left: expr.span.shrink_to_lo(),763 right: expr.span.shrink_to_hi(),764 },765 }),766 _ => {767 // We can end up here even without `<` being the next token, for768 // example because `parse_ty_no_plus` returns `Err` on keywords,769 // but `parse_path` returns `Ok` on them due to error recovery.770 // Return original error and parser state.771 *self = parser_snapshot_after_type;772 return Err(type_err);773 }774 };775776 // Successfully parsed the type path leaving a `<` yet to parse.777 type_err.cancel();778779 // Keep `x as usize` as an expression in AST and continue parsing.780 expr781 }782 Err(path_err) => {783 // Couldn't parse as a path, return original error and parser state.784 path_err.cancel();785 *self = parser_snapshot_after_type;786 return Err(type_err);787 }788 }789 }790 };791792 // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)793 // after a cast. If one is present, emit an error then return a valid794 // parse tree; For something like `&x as T[0]` will be as if it was795 // written `((&x) as T)[0]`.796797 let span = cast_expr.span;798799 let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;800801 // Check if an illegal postfix operator has been added after the cast.802 // If the resulting expression is not a cast, it is an illegal postfix operator.803 if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {804 let msg = format!(805 "cast cannot be followed by {}",806 match with_postfix.kind {807 ExprKind::Index(..) => "indexing",808 ExprKind::Try(_) => "`?`",809 ExprKind::Field(_, _) => "a field access",810 ExprKind::MethodCall(_) => "a method call",811 ExprKind::Call(_, _) => "a function call",812 ExprKind::Await(_, _) => "`.await`",813 ExprKind::Use(_, _) => "`.use`",814 ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",815 ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",816 ExprKind::Err(_) => return Ok(with_postfix),817 _ => unreachable!(818 "did not expect {:?} as an illegal postfix operator following cast",819 with_postfix.kind820 ),821 }822 );823 let mut err = self.dcx().struct_span_err(span, msg);824825 let suggest_parens = |err: &mut Diag<'_>| {826 let suggestions = vec![827 (span.shrink_to_lo(), "(".to_string()),828 (span.shrink_to_hi(), ")".to_string()),829 ];830 err.multipart_suggestion(831 "try surrounding the expression in parentheses",832 suggestions,833 Applicability::MachineApplicable,834 );835 };836837 suggest_parens(&mut err);838839 err.emit();840 };841 Ok(with_postfix)842 }843844 /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.845 fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {846 self.expect_and()?;847 let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);848 let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.849 let (borrow_kind, mutbl) = self.parse_borrow_modifiers();850 let attrs = self.parse_outer_attributes()?;851 let expr = if self.token.is_range_separator() {852 self.parse_expr_prefix_range(attrs)853 } else {854 self.parse_expr_prefix(attrs)855 }?;856 let hi = self.interpolated_or_expr_span(&expr);857 let span = lo.to(hi);858 if let Some(lt) = lifetime {859 self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));860 }861862 // Add expected tokens if we parsed `&raw` as an expression.863 // This will make sure we see "expected `const`, `mut`", and864 // guides recovery in case we write `&raw expr`.865 if borrow_kind == ast::BorrowKind::Ref866 && mutbl == ast::Mutability::Not867 && matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw)868 {869 self.expected_token_types.insert(TokenType::KwMut);870 self.expected_token_types.insert(TokenType::KwConst);871 }872873 Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))874 }875876 fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {877 self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });878 }879880 /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.881 fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {882 if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {883 // `raw [ const | mut ]`.884 let found_raw = self.eat_keyword(exp!(Raw));885 assert!(found_raw);886 let mutability = self.parse_mut_or_const().unwrap();887 (ast::BorrowKind::Raw, mutability)888 } else {889 match self.parse_pin_and_mut() {890 // `mut?`891 (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),892 // `pin [ const | mut ]`.893 // `pin` has been gated in `self.parse_pin_and_mut()` so we don't894 // need to gate it here.895 (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),896 }897 }898 }899900 /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.901 fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {902 self.collect_tokens_for_expr(attrs, |this, attrs| {903 let base = this.parse_expr_bottom()?;904 let span = this.interpolated_or_expr_span(&base);905 this.parse_expr_dot_or_call_with(attrs, base, span)906 })907 }908909 pub(super) fn parse_expr_dot_or_call_with(910 &mut self,911 mut attrs: ast::AttrVec,912 mut e: Box<Expr>,913 lo: Span,914 ) -> PResult<'a, Box<Expr>> {915 let mut res = ensure_sufficient_stack(|| {916 loop {917 let has_question =918 if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {919 // We are using noexpect here because we don't expect a `?` directly after920 // a `return` which could be suggested otherwise.921 self.eat_noexpect(&token::Question)922 } else {923 self.eat(exp!(Question))924 };925 if has_question {926 // `expr?`927 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));928 continue;929 }930 let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {931 // We are using noexpect here because we don't expect a `.` directly after932 // a `return` which could be suggested otherwise.933 self.eat_noexpect(&token::Dot)934 } else if self.token == TokenKind::RArrow && self.may_recover() {935 // Recovery for `expr->suffix`.936 self.bump();937 let span = self.prev_token.span;938 self.dcx().emit_err(errors::ExprRArrowCall { span });939 true940 } else {941 self.eat(exp!(Dot))942 };943 if has_dot {944 // expr.f945 e = self.parse_dot_suffix_expr(lo, e)?;946 continue;947 }948 if self.expr_is_complete(&e) {949 return Ok(e);950 }951 e = match self.token.kind {952 token::OpenParen => self.parse_expr_fn_call(lo, e),953 token::OpenBracket => self.parse_expr_index(lo, e)?,954 _ => return Ok(e),955 }956 }957 });958959 // Stitch the list of outer attributes onto the return value. A little960 // bit ugly, but the best way given the current code structure.961 if !attrs.is_empty()962 && let Ok(expr) = &mut res963 {964 mem::swap(&mut expr.attrs, &mut attrs);965 expr.attrs.extend(attrs)966 }967 res968 }969970 pub(super) fn parse_dot_suffix_expr(971 &mut self,972 lo: Span,973 base: Box<Expr>,974 ) -> PResult<'a, Box<Expr>> {975 // At this point we've consumed something like `expr.` and `self.token` holds the token976 // after the dot.977 match self.token.uninterpolate().kind {978 token::Ident(..) => self.parse_dot_suffix(base, lo),979 token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {980 let ident_span = self.token.span;981 self.bump();982 Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))983 }984 token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {985 Ok(match self.break_up_float(symbol, self.token.span) {986 // 1e2987 DestructuredFloat::Single(sym, _sp) => {988 // `foo.1e2`: a single complete dot access, fully consumed. We end up with989 // the `1e2` token in `self.prev_token` and the following token in990 // `self.token`.991 let ident_span = self.token.span;992 self.bump();993 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)994 }995 // 1.996 DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {997 // `foo.1.`: a single complete dot access and the start of another.998 // We end up with the `sym` (`1`) token in `self.prev_token` and a dot in999 // `self.token`.1000 assert!(suffix.is_none());1001 self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);1002 self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));1003 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)1004 }1005 // 1.2 | 1.2e31006 DestructuredFloat::MiddleDot(1007 sym1,1008 ident1_span,1009 _dot_span,1010 sym2,1011 ident2_span,1012 ) => {1013 // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with1014 // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following1015 // token in `self.token`.1016 let next_token2 =1017 Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);1018 self.bump_with((next_token2, self.token_spacing));1019 self.bump();1020 let base1 =1021 self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);1022 self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)1023 }1024 DestructuredFloat::Error => base,1025 })1026 }1027 _ => {1028 self.error_unexpected_after_dot();1029 Ok(base)1030 }1031 }1032 }10331034 fn error_unexpected_after_dot(&self) {1035 let actual = super::token_descr(&self.token);1036 let span = self.token.span;1037 let sm = self.psess.source_map();1038 let (span, actual) = match (&self.token.kind, self.subparser_name) {1039 (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {1040 (span.shrink_to_hi(), format!("`{}`", snippet))1041 }1042 (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {1043 // No need to report an error. This case will only occur when parsing a pasted1044 // metavariable, and we should have emitted an error when parsing the macro call in1045 // the first place. E.g. in this code:1046 // ```1047 // macro_rules! m { ($e:expr) => { $e }; }1048 //1049 // fn main() {1050 // let f = 1;1051 // m!(f.);1052 // }1053 // ```1054 // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't1055 // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`1056 // represent the invisible delimiters).1057 self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");1058 return;1059 }1060 _ => (span, actual),1061 };1062 self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });1063 }10641065 /// We need an identifier or integer, but the next token is a float.1066 /// Break the float into components to extract the identifier or integer.1067 ///1068 /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.1069 //1070 // FIXME: With current `TokenCursor` it's hard to break tokens into more than 21071 // parts unless those parts are processed immediately. `TokenCursor` should either1072 // support pushing "future tokens" (would be also helpful to `break_and_eat`), or1073 // we should break everything including floats into more basic proc-macro style1074 // tokens in the lexer (probably preferable).1075 pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {1076 #[derive(Debug)]1077 enum FloatComponent {1078 IdentLike(String),1079 Punct(char),1080 }1081 use FloatComponent::*;10821083 let float_str = float.as_str();1084 let mut components = Vec::new();1085 let mut ident_like = String::new();1086 for c in float_str.chars() {1087 if c == '_' || c.is_ascii_alphanumeric() {1088 ident_like.push(c);1089 } else if matches!(c, '.' | '+' | '-') {1090 if !ident_like.is_empty() {1091 components.push(IdentLike(mem::take(&mut ident_like)));1092 }1093 components.push(Punct(c));1094 } else {1095 panic!("unexpected character in a float token: {c:?}")1096 }1097 }1098 if !ident_like.is_empty() {1099 components.push(IdentLike(ident_like));1100 }11011102 // With proc macros the span can refer to anything, the source may be too short,1103 // or too long, or non-ASCII. It only makes sense to break our span into components1104 // if its underlying text is identical to our float literal.1105 let can_take_span_apart =1106 || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();11071108 match &*components {1109 // 1e21110 [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span),1111 // 1.1112 [IdentLike(left), Punct('.')] => {1113 let (left_span, dot_span) = if can_take_span_apart() {1114 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));1115 let dot_span = span.with_lo(left_span.hi());1116 (left_span, dot_span)1117 } else {1118 (span, span)1119 };1120 let left = Symbol::intern(left);1121 DestructuredFloat::TrailingDot(left, left_span, dot_span)1122 }1123 // 1.2 | 1.2e31124 [IdentLike(left), Punct('.'), IdentLike(right)] => {1125 let (left_span, dot_span, right_span) = if can_take_span_apart() {1126 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));1127 let dot_span =1128 span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));1129 let right_span = span.with_lo(dot_span.hi());1130 (left_span, dot_span, right_span)1131 } else {1132 (span, span, span)1133 };1134 let left = Symbol::intern(left);1135 let right = Symbol::intern(right);1136 DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)1137 }1138 // 1e+ | 1e- (recovered)1139 [IdentLike(_), Punct('+' | '-')] |1140 // 1e+2 | 1e-21141 [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |1142 // 1.2e+ | 1.2e-1143 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |1144 // 1.2e+3 | 1.2e-31145 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {1146 // See the FIXME about `TokenCursor` above.1147 self.error_unexpected_after_dot();1148 DestructuredFloat::Error1149 }1150 _ => panic!("unexpected components in a float token: {components:?}"),1151 }1152 }11531154 /// Parse the field access used in offset_of, matched by `$(e:expr)+`.1155 /// Currently returns a list of idents. However, it should be possible in1156 /// future to also do array indices, which might be arbitrary expressions.1157 pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {1158 let mut fields = Vec::new();1159 let mut trailing_dot = None;11601161 loop {1162 // This is expected to use a metavariable $(args:expr)+, but the builtin syntax1163 // could be called directly. Calling `parse_expr` allows this function to only1164 // consider `Expr`s.1165 let expr = self.parse_expr()?;1166 let mut current = &expr;1167 let start_idx = fields.len();1168 loop {1169 match current.kind {1170 ExprKind::Field(ref left, right) => {1171 // Field access is read right-to-left.1172 fields.insert(start_idx, right);1173 trailing_dot = None;1174 current = left;1175 }1176 // Parse this both to give helpful error messages and to1177 // verify it can be done with this parser setup.1178 ExprKind::Index(ref left, ref _right, span) => {1179 self.dcx().emit_err(errors::ArrayIndexInOffsetOf(span));1180 current = left;1181 }1182 ExprKind::Lit(token::Lit {1183 kind: token::Float | token::Integer,1184 symbol,1185 suffix,1186 }) => {1187 if let Some(suffix) = suffix {1188 self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {1189 span: current.span,1190 suffix,1191 });1192 }1193 match self.break_up_float(symbol, current.span) {1194 // 1e21195 DestructuredFloat::Single(sym, sp) => {1196 trailing_dot = None;1197 fields.insert(start_idx, Ident::new(sym, sp));1198 }1199 // 1.1200 DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {1201 assert!(suffix.is_none());1202 trailing_dot = Some(dot_span);1203 fields.insert(start_idx, Ident::new(sym, sym_span));1204 }1205 // 1.2 | 1.2e31206 DestructuredFloat::MiddleDot(1207 symbol1,1208 span1,1209 _dot_span,1210 symbol2,1211 span2,1212 ) => {1213 trailing_dot = None;1214 fields.insert(start_idx, Ident::new(symbol2, span2));1215 fields.insert(start_idx, Ident::new(symbol1, span1));1216 }1217 DestructuredFloat::Error => {1218 trailing_dot = None;1219 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));1220 }1221 }1222 break;1223 }1224 ExprKind::Path(None, Path { ref segments, .. }) => {1225 match &segments[..] {1226 [PathSegment { ident, args: None, .. }] => {1227 trailing_dot = None;1228 fields.insert(start_idx, *ident)1229 }1230 _ => {1231 self.dcx().emit_err(errors::InvalidOffsetOf(current.span));1232 break;1233 }1234 }1235 break;1236 }1237 _ => {1238 self.dcx().emit_err(errors::InvalidOffsetOf(current.span));1239 break;1240 }1241 }1242 }12431244 if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {1245 break;1246 } else if trailing_dot.is_none() {1247 // This loop should only repeat if there is a trailing dot.1248 self.dcx().emit_err(errors::InvalidOffsetOf(self.token.span));1249 break;1250 }1251 }1252 if let Some(dot) = trailing_dot {1253 self.dcx().emit_err(errors::InvalidOffsetOf(dot));1254 }1255 Ok(fields.into_iter().collect())1256 }12571258 fn mk_expr_tuple_field_access(1259 &self,1260 lo: Span,1261 ident_span: Span,1262 base: Box<Expr>,1263 field: Symbol,1264 suffix: Option<Symbol>,1265 ) -> Box<Expr> {1266 if let Some(suffix) = suffix {1267 self.dcx()1268 .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix });1269 }1270 self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))1271 }12721273 /// Parse a function call expression, `expr(...)`.1274 fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {1275 let snapshot = if self.token == token::OpenParen {1276 Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))1277 } else {1278 None1279 };1280 let open_paren = self.token.span;1281 let call_depth = self.token_cursor.stack.len();12821283 let seq = match self.parse_expr_paren_seq() {1284 Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),1285 Err(err)1286 if self.is_expected_raw_ref_mut()1287 && self.token_cursor.stack.len() == call_depth =>1288 {1289 let guar = err.emit();1290 // Preserve the call expression so later passes can still diagnose the callee,1291 // while treating the malformed `&raw <expr>` argument as an error expression.1292 let args = self.recover_raw_ref_call_args(guar);1293 return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));1294 }1295 Err(err) => Err(err),1296 };1297 match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {1298 Ok(expr) => expr,1299 Err(err) => self.recover_seq_parse_error(exp!(OpenParen), exp!(CloseParen), lo, err),1300 }1301 }13021303 fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {1304 let err_span = self.prev_token.span.to(self.token.span);1305 let mut args = thin_vec![self.mk_expr_err(err_span, guar)];1306 while !self.token.kind.is_close_delim_or_eof() {1307 if self.eat(exp!(Comma)) && !self.token.kind.is_close_delim_or_eof() {1308 args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));1309 } else {1310 self.parse_token_tree();1311 }1312 }1313 let _ = self.eat(exp!(CloseParen));1314 args1315 }13161317 /// If we encounter a parser state that looks like the user has written a `struct` literal with1318 /// parentheses instead of braces, recover the parser state and provide suggestions.1319 #[instrument(skip(self, seq, snapshot), level = "trace")]1320 fn maybe_recover_struct_lit_bad_delims(1321 &mut self,1322 lo: Span,1323 open_paren: Span,1324 seq: PResult<'a, Box<Expr>>,1325 snapshot: Option<(SnapshotParser<'a>, ExprKind)>,1326 ) -> PResult<'a, Box<Expr>> {1327 match (self.may_recover(), seq, snapshot) {1328 (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {1329 snapshot.bump(); // `(`1330 match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {1331 Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {1332 // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest1333 // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.1334 self.restore_snapshot(snapshot);1335 let close_paren = self.prev_token.span;1336 let span = lo.to(close_paren);1337 // filter shorthand fields1338 let fields: Vec<_> =1339 fields.into_iter().filter(|field| !field.is_shorthand).collect();13401341 let guar = if !fields.is_empty() &&1342 // `token.kind` should not be compared here.1343 // This is because the `snapshot.token.kind` is treated as the same as1344 // that of the open delim in `TokenTreesReader::parse_token_tree`, even1345 // if they are different.1346 self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")1347 {1348 err.cancel();1349 let type_str = pprust::path_to_string(&path);1350 self.dcx()1351 .create_err(errors::ParenthesesWithStructFields {1352 span,1353 braces_for_struct: errors::BracesForStructLiteral {1354 first: open_paren,1355 second: close_paren,1356 r#type: type_str.clone(),1357 },1358 no_fields_for_fn: errors::NoFieldsForFnCall {1359 r#type: type_str,1360 fields: fields1361 .into_iter()1362 .map(|field| field.span.until(field.expr.span))1363 .collect(),1364 },1365 })1366 .emit()1367 } else {1368 err.emit()1369 };1370 Ok(self.mk_expr_err(span, guar))1371 }1372 Ok(_) => Err(err),1373 Err(err2) => {1374 err2.cancel();1375 Err(err)1376 }1377 }1378 }1379 (_, seq, _) => seq,1380 }1381 }13821383 /// Parse an indexing expression `expr[...]`.1384 fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {1385 let prev_span = self.prev_token.span;1386 let open_delim_span = self.token.span;1387 self.bump(); // `[`1388 let index = self.parse_expr()?;1389 self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;1390 self.expect(exp!(CloseBracket))?;1391 Ok(self.mk_expr(1392 lo.to(self.prev_token.span),1393 self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),1394 ))1395 }13961397 /// Assuming we have just parsed `.`, continue parsing into an expression.1398 fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {1399 if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) {1400 return Ok(self.mk_await_expr(self_arg, lo));1401 }14021403 if self.eat_keyword(exp!(Use)) {1404 let use_span = self.prev_token.span;1405 self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);1406 return Ok(self.mk_use_expr(self_arg, lo));1407 }14081409 // Post-fix match1410 if self.eat_keyword(exp!(Match)) {1411 let match_span = self.prev_token.span;1412 self.psess.gated_spans.gate(sym::postfix_match, match_span);1413 return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);1414 }14151416 // Parse a postfix `yield`.1417 if self.eat_keyword(exp!(Yield)) {1418 let yield_span = self.prev_token.span;1419 self.psess.gated_spans.gate(sym::yield_expr, yield_span);1420 return Ok(1421 self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))1422 );1423 }14241425 let fn_span_lo = self.token.span;1426 let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;1427 self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);1428 self.check_turbofish_missing_angle_brackets(&mut seg);14291430 if self.check(exp!(OpenParen)) {1431 // Method call `expr.f()`1432 let args = self.parse_expr_paren_seq()?;1433 let fn_span = fn_span_lo.to(self.prev_token.span);1434 let span = lo.to(self.prev_token.span);1435 Ok(self.mk_expr(1436 span,1437 ExprKind::MethodCall(Box::new(ast::MethodCall {1438 seg,1439 receiver: self_arg,1440 args,1441 span: fn_span,1442 })),1443 ))1444 } else {1445 // Field access `expr.f`1446 let span = lo.to(self.prev_token.span);1447 if let Some(args) = seg.args {1448 // See `StashKey::GenericInFieldExpr` for more info on why we stash this.1449 self.dcx()1450 .create_err(errors::FieldExpressionWithGeneric(args.span()))1451 .stash(seg.ident.span, StashKey::GenericInFieldExpr);1452 }14531454 Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))1455 }1456 }14571458 /// At the bottom (top?) of the precedence hierarchy,1459 /// Parses things like parenthesized exprs, macros, `return`, etc.1460 ///1461 /// N.B., this does not parse outer attributes, and is private because it only works1462 /// correctly if called from `parse_expr_dot_or_call`.1463 fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {1464 maybe_recover_from_interpolated_ty_qpath!(self, true);14651466 let span = self.token.span;1467 if let Some(expr) = self.eat_metavar_seq_with_matcher(1468 |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),1469 |this| {1470 // Force collection (as opposed to just `parse_expr`) is required to avoid the1471 // attribute duplication seen in #138478.1472 let expr = this.parse_expr_force_collect();1473 // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly1474 // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line1475 // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in1476 // `compiler/rustc_index/src/bit_set/tests.rs`.1477 if this.token.kind == token::Comma {1478 this.bump();1479 }1480 expr1481 },1482 ) {1483 return Ok(expr);1484 } else if let Some(lit) =1485 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())1486 {1487 return Ok(lit);1488 } else if let Some(block) =1489 self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())1490 {1491 return Ok(self.mk_expr(span, ExprKind::Block(block, None)));1492 } else if let Some(path) =1493 self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))1494 {1495 return Ok(self.mk_expr(span, ExprKind::Path(None, path)));1496 }14971498 // Outer attributes are already parsed and will be1499 // added to the return value after the fact.15001501 let restrictions = self.restrictions;1502 self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {1503 // Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.1504 let lo = this.token.span;1505 if let token::Literal(_) = this.token.kind {1506 // This match arm is a special-case of the `_` match arm below and1507 // could be removed without changing functionality, but it's faster1508 // to have it here, especially for programs with large constants.1509 this.parse_expr_lit()1510 } else if this.check(exp!(OpenParen)) {1511 this.parse_expr_tuple_parens(restrictions)1512 } else if this.check(exp!(OpenBrace)) {1513 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {1514 return Ok(expr);1515 }1516 this.parse_expr_block(None, lo, BlockCheckMode::Default)1517 } else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {1518 this.parse_expr_closure().map_err(|mut err| {1519 // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`1520 // then suggest parens around the lhs.1521 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {1522 err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));1523 }1524 err1525 })1526 } else if this.check(exp!(OpenBracket)) {1527 this.parse_expr_array_or_repeat(exp!(CloseBracket))1528 } else if this.is_builtin() {1529 this.parse_expr_builtin()1530 } else if this.check_path() {1531 this.parse_expr_path_start()1532 } else if this.check_keyword(exp!(Move))1533 || this.check_keyword(exp!(Use))1534 || this.check_keyword(exp!(Static))1535 || this.check_const_closure()1536 {1537 this.parse_expr_closure()1538 } else if this.eat_keyword(exp!(If)) {1539 this.parse_expr_if()1540 } else if this.check_keyword(exp!(For)) {1541 if this.choose_generics_over_qpath(1) {1542 this.parse_expr_closure()1543 } else {1544 assert!(this.eat_keyword(exp!(For)));1545 this.parse_expr_for(None, lo)1546 }1547 } else if this.eat_keyword(exp!(While)) {1548 this.parse_expr_while(None, lo)1549 } else if let Some(label) = this.eat_label() {1550 this.parse_expr_labeled(label, true)1551 } else if this.eat_keyword(exp!(Loop)) {1552 this.parse_expr_loop(None, lo).map_err(|mut err| {1553 err.span_label(lo, "while parsing this `loop` expression");1554 err1555 })1556 } else if this.eat_keyword(exp!(Match)) {1557 this.parse_expr_match().map_err(|mut err| {1558 err.span_label(lo, "while parsing this `match` expression");1559 err1560 })1561 } else if this.eat_keyword(exp!(Unsafe)) {1562 this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(1563 |mut err| {1564 err.span_label(lo, "while parsing this `unsafe` expression");1565 err1566 },1567 )1568 } else if this.check_inline_const(0) {1569 this.parse_const_block(lo, false)1570 } else if this.may_recover() && this.is_do_catch_block() {1571 this.recover_do_catch()1572 } else if this.is_try_block() {1573 this.expect_keyword(exp!(Try))?;1574 this.parse_try_block(lo)1575 } else if this.eat_keyword(exp!(Return)) {1576 this.parse_expr_return()1577 } else if this.eat_keyword(exp!(Continue)) {1578 this.parse_expr_continue(lo)1579 } else if this.eat_keyword(exp!(Break)) {1580 this.parse_expr_break()1581 } else if this.eat_keyword(exp!(Yield)) {1582 this.parse_expr_yield()1583 } else if this.is_do_yeet() {1584 this.parse_expr_yeet()1585 } else if this.eat_keyword(exp!(Become)) {1586 this.parse_expr_become()1587 } else if this.check_keyword(exp!(Let)) {1588 this.parse_expr_let(restrictions)1589 } else if this.eat_keyword(exp!(Underscore)) {1590 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {1591 return Ok(expr);1592 }1593 Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))1594 } else if this.token_uninterpolated_span().at_least_rust_2018() {1595 // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.1596 let at_async = this.check_keyword(exp!(Async));1597 // check for `gen {}` and `gen move {}`1598 // or `async gen {}` and `async gen move {}`1599 // FIXME: (async) gen closures aren't yet parsed.1600 // FIXME(gen_blocks): Parse `gen async` and suggest swap1601 if this.token_uninterpolated_span().at_least_rust_2024()1602 && this.is_gen_block(kw::Gen, at_async as usize)1603 {1604 this.parse_gen_block()1605 // Check for `async {` and `async move {`,1606 } else if this.is_gen_block(kw::Async, 0) {1607 this.parse_gen_block()1608 } else if at_async {1609 this.parse_expr_closure()1610 } else if this.eat_keyword_noexpect(kw::Await) {1611 this.recover_incorrect_await_syntax(lo)1612 } else {1613 this.parse_expr_lit()1614 }1615 } else {1616 this.parse_expr_lit()1617 }1618 })1619 }16201621 fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {1622 let lo = self.token.span;1623 match self.parse_opt_token_lit() {1624 Some((token_lit, _)) => {1625 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));1626 self.maybe_recover_from_bad_qpath(expr)1627 }1628 None => self.try_macro_suggestion(),1629 }1630 }16311632 fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {1633 let lo = self.token.span;1634 self.expect(exp!(OpenParen))?;1635 let (es, trailing_comma) = match self.parse_seq_to_end(1636 exp!(CloseParen),1637 SeqSep::trailing_allowed(exp!(Comma)),1638 |p| p.parse_expr_catch_underscore(restrictions.intersection(Restrictions::ALLOW_LET)),1639 ) {1640 Ok(x) => x,1641 Err(err) => {1642 return Ok(self.recover_seq_parse_error(1643 exp!(OpenParen),1644 exp!(CloseParen),1645 lo,1646 err,1647 ));1648 }1649 };1650 let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) {1651 // `(e)` is parenthesized `e`.1652 ExprKind::Paren(es.into_iter().next().unwrap())1653 } else {1654 // `(e,)` is a tuple with only one field, `e`.1655 ExprKind::Tup(es)1656 };1657 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1658 self.maybe_recover_from_bad_qpath(expr)1659 }16601661 fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {1662 let lo = self.token.span;1663 self.bump(); // `[` or other open delim16641665 let kind = if self.eat(close) {1666 // Empty vector1667 ExprKind::Array(ThinVec::new())1668 } else {1669 // Non-empty vector1670 let first_expr = self.parse_expr()?;1671 if self.eat(exp!(Semi)) {1672 // Repeating array syntax: `[ 0; 512 ]`1673 let count = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?;1674 self.expect(close)?;1675 ExprKind::Repeat(first_expr, count)1676 } else if self.eat(exp!(Comma)) {1677 // Vector with two or more elements.1678 let sep = SeqSep::trailing_allowed(exp!(Comma));1679 let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;1680 exprs.insert(0, first_expr);1681 ExprKind::Array(exprs)1682 } else {1683 // Vector with one element1684 self.expect(close)?;1685 ExprKind::Array(thin_vec![first_expr])1686 }1687 };1688 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1689 self.maybe_recover_from_bad_qpath(expr)1690 }16911692 fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {1693 let maybe_eq_tok = self.prev_token;1694 let (qself, path) = if self.eat_lt() {1695 let lt_span = self.prev_token.span;1696 let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {1697 // Suggests using '<=' if there is an error parsing qpath when the previous token1698 // is an '=' token. Only emits suggestion if the '<' token and '=' token are1699 // directly adjacent (i.e. '=<')1700 if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {1701 let eq_lt = maybe_eq_tok.span.to(lt_span);1702 err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);1703 }1704 err1705 })?;1706 (Some(qself), path)1707 } else {1708 (None, self.parse_path(PathStyle::Expr)?)1709 };17101711 // `!`, as an operator, is prefix, so we know this isn't that.1712 let (span, kind) = if self.eat(exp!(Bang)) {1713 // MACRO INVOCATION expression1714 if qself.is_some() {1715 self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span));1716 }1717 let lo = path.span;1718 let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });1719 (lo.to(self.prev_token.span), ExprKind::MacCall(mac))1720 } else if self.check(exp!(OpenBrace))1721 && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)1722 {1723 if qself.is_some() {1724 self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);1725 }1726 return expr;1727 } else {1728 (path.span, ExprKind::Path(qself, path))1729 };17301731 let expr = self.mk_expr(span, kind);1732 self.maybe_recover_from_bad_qpath(expr)1733 }17341735 /// Parse `'label: $expr`. The label is already parsed.1736 pub(super) fn parse_expr_labeled(1737 &mut self,1738 label_: Label,1739 mut consume_colon: bool,1740 ) -> PResult<'a, Box<Expr>> {1741 let lo = label_.ident.span;1742 let label = Some(label_);1743 let ate_colon = self.eat(exp!(Colon));1744 let tok_sp = self.token.span;1745 let expr = if self.eat_keyword(exp!(While)) {1746 self.parse_expr_while(label, lo)1747 } else if self.eat_keyword(exp!(For)) {1748 self.parse_expr_for(label, lo)1749 } else if self.eat_keyword(exp!(Loop)) {1750 self.parse_expr_loop(label, lo)1751 } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {1752 self.parse_expr_block(label, lo, BlockCheckMode::Default)1753 } else if !ate_colon1754 && self.may_recover()1755 && (self.token.kind.close_delim().is_some() || self.token.is_punct())1756 && could_be_unclosed_char_literal(label_.ident)1757 {1758 let (lit, _) =1759 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {1760 self_.dcx().create_err(errors::UnexpectedTokenAfterLabel {1761 span: self_.token.span,1762 remove_label: None,1763 enclose_in_block: None,1764 })1765 });1766 consume_colon = false;1767 Ok(self.mk_expr(lo, ExprKind::Lit(lit)))1768 } else if !ate_colon1769 && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))1770 {1771 // We're probably inside of a `Path<'a>` that needs a turbofish1772 let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {1773 span: self.token.span,1774 remove_label: None,1775 enclose_in_block: None,1776 });1777 consume_colon = false;1778 Ok(self.mk_expr_err(lo, guar))1779 } else {1780 let mut err = errors::UnexpectedTokenAfterLabel {1781 span: self.token.span,1782 remove_label: None,1783 enclose_in_block: None,1784 };17851786 // Continue as an expression in an effort to recover on `'label: non_block_expr`.1787 let expr = self.parse_expr().map(|expr| {1788 let span = expr.span;17891790 let found_labeled_breaks = {1791 struct FindLabeledBreaksVisitor;17921793 impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {1794 type Result = ControlFlow<()>;1795 fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {1796 if let ExprKind::Break(Some(_label), _) = ex.kind {1797 ControlFlow::Break(())1798 } else {1799 walk_expr(self, ex)1800 }1801 }1802 }18031804 FindLabeledBreaksVisitor.visit_expr(&expr).is_break()1805 };18061807 // Suggestion involves adding a labeled block.1808 //1809 // If there are no breaks that may use this label, suggest removing the label and1810 // recover to the unmodified expression.1811 if !found_labeled_breaks {1812 err.remove_label = Some(lo.until(span));18131814 return expr;1815 }18161817 err.enclose_in_block = Some(errors::UnexpectedTokenAfterLabelSugg {1818 left: span.shrink_to_lo(),1819 right: span.shrink_to_hi(),1820 });18211822 // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.1823 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));1824 let blk = self.mk_block(thin_vec![stmt], BlockCheckMode::Default, span);1825 self.mk_expr(span, ExprKind::Block(blk, label))1826 });18271828 self.dcx().emit_err(err);1829 expr1830 }?;18311832 if !ate_colon && consume_colon {1833 self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {1834 span: expr.span,1835 label: lo,1836 label_end: lo.between(tok_sp),1837 });1838 }18391840 Ok(expr)1841 }18421843 /// Emit an error when a char is parsed as a lifetime or label because of a missing quote.1844 pub(super) fn recover_unclosed_char<L>(1845 &self,1846 ident: Ident,1847 mk_lit_char: impl FnOnce(Symbol, Span) -> L,1848 err: impl FnOnce(&Self) -> Diag<'a>,1849 ) -> L {1850 assert!(could_be_unclosed_char_literal(ident));1851 self.dcx()1852 .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {1853 err.span_suggestion_verbose(1854 ident.span.shrink_to_hi(),1855 "add `'` to close the char literal",1856 "'",1857 Applicability::MaybeIncorrect,1858 );1859 })1860 .unwrap_or_else(|| {1861 err(self)1862 .with_span_suggestion_verbose(1863 ident.span.shrink_to_hi(),1864 "add `'` to close the char literal",1865 "'",1866 Applicability::MaybeIncorrect,1867 )1868 .emit()1869 });1870 let name = ident.without_first_quote().name;1871 mk_lit_char(name, ident.span)1872 }18731874 /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.1875 fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {1876 let lo = self.token.span;18771878 self.bump(); // `do`1879 self.bump(); // `catch`18801881 let span = lo.to(self.prev_token.span);1882 self.dcx().emit_err(errors::DoCatchSyntaxRemoved { span });18831884 self.parse_try_block(lo)1885 }18861887 /// Parse an expression if the token can begin one.1888 fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {1889 Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })1890 }18911892 /// Parse `"return" expr?`.1893 fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {1894 let lo = self.prev_token.span;1895 let kind = ExprKind::Ret(self.parse_expr_opt()?);1896 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);1897 self.maybe_recover_from_bad_qpath(expr)1898 }18991900 /// Parse `"do" "yeet" expr?`.1901 fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {1902 let lo = self.token.span;19031904 self.bump(); // `do`1905 self.bump(); // `yeet`19061907 let kind = ExprKind::Yeet(self.parse_expr_opt()?);19081909 let span = lo.to(self.prev_token.span);1910 self.psess.gated_spans.gate(sym::yeet_expr, span);1911 let expr = self.mk_expr(span, kind);1912 self.maybe_recover_from_bad_qpath(expr)1913 }19141915 /// Parse `"become" expr`, with `"become"` token already eaten.1916 fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {1917 let lo = self.prev_token.span;1918 let kind = ExprKind::Become(self.parse_expr()?);1919 let span = lo.to(self.prev_token.span);1920 self.psess.gated_spans.gate(sym::explicit_tail_calls, span);1921 let expr = self.mk_expr(span, kind);1922 self.maybe_recover_from_bad_qpath(expr)1923 }19241925 /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.1926 /// If the label is followed immediately by a `:` token, the label and `:` are1927 /// parsed as part of the expression (i.e. a labeled loop). The language team has1928 /// decided in #87026 to require parentheses as a visual aid to avoid confusion if1929 /// the break expression of an unlabeled break is a labeled loop (as in1930 /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value1931 /// expression only gets a warning for compatibility reasons; and a labeled break1932 /// with a labeled loop does not even get a warning because there is no ambiguity.1933 fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {1934 let lo = self.prev_token.span;1935 let mut label = self.eat_label();1936 let kind = if self.token == token::Colon1937 && let Some(label) = label.take()1938 {1939 // The value expression can be a labeled loop, see issue #86948, e.g.:1940 // `loop { break 'label: loop { break 'label 42; }; }`1941 let lexpr = self.parse_expr_labeled(label, true)?;1942 self.dcx().emit_err(errors::LabeledLoopInBreak {1943 span: lexpr.span,1944 sub: errors::WrapInParentheses::Expression {1945 left: lexpr.span.shrink_to_lo(),1946 right: lexpr.span.shrink_to_hi(),1947 },1948 });1949 Some(lexpr)1950 } else if self.token != token::OpenBrace1951 || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)1952 {1953 let mut expr = self.parse_expr_opt()?;1954 if let Some(expr) = &mut expr {1955 if label.is_some()1956 && match &expr.kind {1957 ExprKind::While(_, _, None)1958 | ExprKind::ForLoop { label: None, .. }1959 | ExprKind::Loop(_, None, _) => true,1960 ExprKind::Block(block, None) => {1961 matches!(block.rules, BlockCheckMode::Default)1962 }1963 _ => false,1964 }1965 {1966 let span = expr.span;1967 self.psess.buffer_lint(1968 BREAK_WITH_LABEL_AND_LOOP,1969 lo.to(expr.span),1970 ast::CRATE_NODE_ID,1971 errors::BreakWithLabelAndLoop {1972 sub: errors::BreakWithLabelAndLoopSub {1973 left: span.shrink_to_lo(),1974 right: span.shrink_to_hi(),1975 },1976 },1977 );1978 }19791980 // Recover `break label aaaaa`1981 if self.may_recover()1982 && let ExprKind::Path(None, p) = &expr.kind1983 && let [segment] = &*p.segments1984 && let &ast::PathSegment { ident, args: None, .. } = segment1985 && let Some(next) = self.parse_expr_opt()?1986 {1987 label = Some(self.recover_ident_into_label(ident));1988 *expr = next;1989 }1990 }19911992 expr1993 } else {1994 None1995 };1996 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));1997 self.maybe_recover_from_bad_qpath(expr)1998 }19992000 /// Parse `"continue" label?`.
Findings
✓ No findings reported for this file.