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