1 use super::attr::InnerAttrForbiddenReason; 2 use super::diagnostics::AttemptLocalParseRecovery; 3 use super::expr::LhsExpr; 4 use super::pat::{PatternLocation, RecoverComma}; 5 use super::path::PathStyle; 6 use super::TrailingToken; 7 use super::{ 8 AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode, 9 }; 10 use crate::errors; 11 use crate::maybe_whole; 12 13 use crate::errors::MalformedLoopLabel; 14 use ast::Label; 15 use rustc_ast as ast; 16 use rustc_ast::ptr::P; 17 use rustc_ast::token::{self, Delimiter, TokenKind}; 18 use rustc_ast::util::classify; 19 use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle}; 20 use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; 21 use rustc_ast::{StmtKind, DUMMY_NODE_ID}; 22 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; 23 use rustc_span::source_map::{BytePos, Span}; 24 use rustc_span::symbol::{kw, sym, Ident}; 25 26 use std::borrow::Cow; 27 use std::mem; 28 use thin_vec::{thin_vec, ThinVec}; 29 30 impl<'a> Parser<'a> { 31 /// Parses a statement. This stops just before trailing semicolons on everything but items. 32 /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. 33 // Public for rustfmt usage. parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>>34 pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { 35 Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|mut e| { 36 e.emit(); 37 self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); 38 None 39 })) 40 } 41 42 /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether 43 /// or not we have attributes 44 // Public for `cfg_eval` macro expansion. parse_stmt_without_recovery( &mut self, capture_semi: bool, force_collect: ForceCollect, ) -> PResult<'a, Option<Stmt>>45 pub fn parse_stmt_without_recovery( 46 &mut self, 47 capture_semi: bool, 48 force_collect: ForceCollect, 49 ) -> PResult<'a, Option<Stmt>> { 50 let attrs = self.parse_outer_attributes()?; 51 let lo = self.token.span; 52 53 // Don't use `maybe_whole` so that we have precise control 54 // over when we bump the parser 55 if let token::Interpolated(nt) = &self.token.kind && let token::NtStmt(stmt) = &**nt { 56 let mut stmt = stmt.clone(); 57 self.bump(); 58 stmt.visit_attrs(|stmt_attrs| { 59 attrs.prepend_to_nt_inner(stmt_attrs); 60 }); 61 return Ok(Some(stmt.into_inner())); 62 } 63 64 if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) { 65 self.bump(); 66 let mut_let_span = lo.to(self.token.span); 67 self.sess.emit_err(errors::InvalidVariableDeclaration { 68 span: mut_let_span, 69 sub: errors::InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span), 70 }); 71 } 72 73 Ok(Some(if self.token.is_keyword(kw::Let) { 74 self.parse_local_mk(lo, attrs, capture_semi, force_collect)? 75 } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() { 76 self.recover_stmt_local_after_let( 77 lo, 78 attrs, 79 errors::InvalidVariableDeclarationSub::MissingLet, 80 )? 81 } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() { 82 self.bump(); // `auto` 83 self.recover_stmt_local_after_let( 84 lo, 85 attrs, 86 errors::InvalidVariableDeclarationSub::UseLetNotAuto, 87 )? 88 } else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() { 89 self.bump(); // `var` 90 self.recover_stmt_local_after_let( 91 lo, 92 attrs, 93 errors::InvalidVariableDeclarationSub::UseLetNotVar, 94 )? 95 } else if self.check_path() 96 && !self.token.is_qpath_start() 97 && !self.is_path_start_item() 98 && !self.is_builtin() 99 { 100 // We have avoided contextual keywords like `union`, items with `crate` visibility, 101 // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something 102 // that starts like a path (1 token), but it fact not a path. 103 // Also, we avoid stealing syntax from `parse_item_`. 104 match force_collect { 105 ForceCollect::Yes => { 106 self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))? 107 } 108 ForceCollect::No => match self.parse_stmt_path_start(lo, attrs) { 109 Ok(stmt) => stmt, 110 Err(mut err) => { 111 self.suggest_add_missing_let_for_stmt(&mut err); 112 return Err(err); 113 } 114 }, 115 } 116 } else if let Some(item) = self.parse_item_common( 117 attrs.clone(), 118 false, 119 true, 120 FnParseMode { req_name: |_| true, req_body: true }, 121 force_collect, 122 )? { 123 // FIXME: Bad copy of attrs 124 self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) 125 } else if self.eat(&token::Semi) { 126 // Do not attempt to parse an expression if we're done here. 127 self.error_outer_attrs(attrs); 128 self.mk_stmt(lo, StmtKind::Empty) 129 } else if self.token != token::CloseDelim(Delimiter::Brace) { 130 // Remainder are line-expr stmts. 131 let e = match force_collect { 132 ForceCollect::Yes => self.collect_tokens_no_attrs(|this| { 133 this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs)) 134 })?, 135 ForceCollect::No => self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?, 136 }; 137 if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(kw::Else) { 138 let bl = self.parse_block()?; 139 // Destructuring assignment ... else. 140 // This is not allowed, but point it out in a nice way. 141 self.sess.emit_err(errors::AssignmentElseNotAllowed { span: e.span.to(bl.span) }); 142 } 143 self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) 144 } else { 145 self.error_outer_attrs(attrs); 146 return Ok(None); 147 })) 148 } 149 parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt>150 fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> { 151 let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { 152 let path = this.parse_path(PathStyle::Expr)?; 153 154 if this.eat(&token::Not) { 155 let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?; 156 if this.token == token::Semi { 157 return Ok((stmt_mac, TrailingToken::Semi)); 158 } else { 159 return Ok((stmt_mac, TrailingToken::None)); 160 } 161 } 162 163 let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) { 164 this.parse_expr_struct(None, path, true)? 165 } else { 166 let hi = this.prev_token.span; 167 this.mk_expr(lo.to(hi), ExprKind::Path(None, path)) 168 }; 169 170 let expr = this.with_res(Restrictions::STMT_EXPR, |this| { 171 this.parse_expr_dot_or_call_with(expr, lo, attrs) 172 })?; 173 // `DUMMY_SP` will get overwritten later in this function 174 Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None)) 175 })?; 176 177 if let StmtKind::Expr(expr) = stmt.kind { 178 // Perform this outside of the `collect_tokens_trailing_token` closure, 179 // since our outer attributes do not apply to this part of the expression 180 let expr = self.with_res(Restrictions::STMT_EXPR, |this| { 181 this.parse_expr_assoc_with( 182 0, 183 LhsExpr::AlreadyParsed { expr, starts_statement: true }, 184 ) 185 })?; 186 Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) 187 } else { 188 Ok(stmt) 189 } 190 } 191 192 /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. 193 /// At this point, the `!` token after the path has already been eaten. parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt>194 fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> { 195 let args = self.parse_delim_args()?; 196 let delim = args.delim.to_token(); 197 let hi = self.prev_token.span; 198 199 let style = match delim { 200 Delimiter::Brace => MacStmtStyle::Braces, 201 _ => MacStmtStyle::NoBraces, 202 }; 203 204 let mac = P(MacCall { path, args }); 205 206 let kind = if (style == MacStmtStyle::Braces 207 && self.token != token::Dot 208 && self.token != token::Question) 209 || self.token == token::Semi 210 || self.token == token::Eof 211 { 212 StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) 213 } else { 214 // Since none of the above applied, this is an expression statement macro. 215 let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); 216 let e = self.maybe_recover_from_bad_qpath(e)?; 217 let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?; 218 let e = self.parse_expr_assoc_with( 219 0, 220 LhsExpr::AlreadyParsed { expr: e, starts_statement: false }, 221 )?; 222 StmtKind::Expr(e) 223 }; 224 Ok(self.mk_stmt(lo.to(hi), kind)) 225 } 226 227 /// Error on outer attributes in this context. 228 /// Also error if the previous token was a doc comment. error_outer_attrs(&self, attrs: AttrWrapper)229 fn error_outer_attrs(&self, attrs: AttrWrapper) { 230 if !attrs.is_empty() 231 && let attrs = attrs.take_for_recovery(self.sess) 232 && let attrs @ [.., last] = &*attrs { 233 if last.is_doc_comment() { 234 self.sess.emit_err(errors::DocCommentDoesNotDocumentAnything { 235 span: last.span, 236 missing_comma: None, 237 }); 238 } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { 239 self.sess.emit_err(errors::ExpectedStatementAfterOuterAttr { span: last.span }); 240 } 241 } 242 } 243 recover_stmt_local_after_let( &mut self, lo: Span, attrs: AttrWrapper, subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub, ) -> PResult<'a, Stmt>244 fn recover_stmt_local_after_let( 245 &mut self, 246 lo: Span, 247 attrs: AttrWrapper, 248 subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub, 249 ) -> PResult<'a, Stmt> { 250 let stmt = 251 self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| { 252 let local = this.parse_local(attrs)?; 253 // FIXME - maybe capture semicolon in recovery? 254 Ok(( 255 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), 256 TrailingToken::None, 257 )) 258 })?; 259 self.sess.emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) }); 260 Ok(stmt) 261 } 262 parse_local_mk( &mut self, lo: Span, attrs: AttrWrapper, capture_semi: bool, force_collect: ForceCollect, ) -> PResult<'a, Stmt>263 fn parse_local_mk( 264 &mut self, 265 lo: Span, 266 attrs: AttrWrapper, 267 capture_semi: bool, 268 force_collect: ForceCollect, 269 ) -> PResult<'a, Stmt> { 270 self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { 271 this.expect_keyword(kw::Let)?; 272 let local = this.parse_local(attrs)?; 273 let trailing = if capture_semi && this.token.kind == token::Semi { 274 TrailingToken::Semi 275 } else { 276 TrailingToken::None 277 }; 278 Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), trailing)) 279 }) 280 } 281 282 /// Parses a local variable declaration. parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>>283 fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> { 284 let lo = self.prev_token.span; 285 286 if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) { 287 self.sess.emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) }); 288 self.bump(); 289 } 290 291 let (pat, colon) = 292 self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?; 293 294 let (err, ty) = if colon { 295 // Save the state of the parser before parsing type normally, in case there is a `:` 296 // instead of an `=` typo. 297 let parser_snapshot_before_type = self.clone(); 298 let colon_sp = self.prev_token.span; 299 match self.parse_ty() { 300 Ok(ty) => (None, Some(ty)), 301 Err(mut err) => { 302 if let Ok(snip) = self.span_to_snippet(pat.span) { 303 err.span_label(pat.span, format!("while parsing the type for `{}`", snip)); 304 } 305 // we use noexpect here because we don't actually expect Eq to be here 306 // but we are still checking for it in order to be able to handle it if 307 // it is there 308 let err = if self.check_noexpect(&token::Eq) { 309 err.emit(); 310 None 311 } else { 312 // Rewind to before attempting to parse the type and continue parsing. 313 let parser_snapshot_after_type = 314 mem::replace(self, parser_snapshot_before_type); 315 Some((parser_snapshot_after_type, colon_sp, err)) 316 }; 317 (err, None) 318 } 319 } 320 } else { 321 (None, None) 322 }; 323 let init = match (self.parse_initializer(err.is_some()), err) { 324 (Ok(init), None) => { 325 // init parsed, ty parsed 326 init 327 } 328 (Ok(init), Some((_, colon_sp, mut err))) => { 329 // init parsed, ty error 330 // Could parse the type as if it were the initializer, it is likely there was a 331 // typo in the code: `:` instead of `=`. Add suggestion and emit the error. 332 err.span_suggestion_short( 333 colon_sp, 334 "use `=` if you meant to assign", 335 " =", 336 Applicability::MachineApplicable, 337 ); 338 err.emit(); 339 // As this was parsed successfully, continue as if the code has been fixed for the 340 // rest of the file. It will still fail due to the emitted error, but we avoid 341 // extra noise. 342 init 343 } 344 (Err(init_err), Some((snapshot, _, ty_err))) => { 345 // init error, ty error 346 init_err.cancel(); 347 // Couldn't parse the type nor the initializer, only raise the type error and 348 // return to the parser state before parsing the type as the initializer. 349 // let x: <parse_error>; 350 *self = snapshot; 351 return Err(ty_err); 352 } 353 (Err(err), None) => { 354 // init error, ty parsed 355 // Couldn't parse the initializer and we're not attempting to recover a failed 356 // parse of the type, return the error. 357 return Err(err); 358 } 359 }; 360 let kind = match init { 361 None => LocalKind::Decl, 362 Some(init) => { 363 if self.eat_keyword(kw::Else) { 364 if self.token.is_keyword(kw::If) { 365 // `let...else if`. Emit the same error that `parse_block()` would, 366 // but explicitly point out that this pattern is not allowed. 367 let msg = "conditional `else if` is not supported for `let...else`"; 368 return Err(self.error_block_no_opening_brace_msg(Cow::from(msg))); 369 } 370 let els = self.parse_block()?; 371 self.check_let_else_init_bool_expr(&init); 372 self.check_let_else_init_trailing_brace(&init); 373 LocalKind::InitElse(init, els) 374 } else { 375 LocalKind::Init(init) 376 } 377 } 378 }; 379 let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span }; 380 Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) 381 } 382 check_let_else_init_bool_expr(&self, init: &ast::Expr)383 fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { 384 if let ast::ExprKind::Binary(op, ..) = init.kind { 385 if op.node.lazy() { 386 self.sess.emit_err(errors::InvalidExpressionInLetElse { 387 span: init.span, 388 operator: op.node.to_string(), 389 sugg: errors::WrapExpressionInParentheses { 390 left: init.span.shrink_to_lo(), 391 right: init.span.shrink_to_hi(), 392 }, 393 }); 394 } 395 } 396 } 397 check_let_else_init_trailing_brace(&self, init: &ast::Expr)398 fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) { 399 if let Some(trailing) = classify::expr_trailing_brace(init) { 400 self.sess.emit_err(errors::InvalidCurlyInLetElse { 401 span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)), 402 sugg: errors::WrapExpressionInParentheses { 403 left: trailing.span.shrink_to_lo(), 404 right: trailing.span.shrink_to_hi(), 405 }, 406 }); 407 } 408 } 409 410 /// Parses the RHS of a local variable declaration (e.g., `= 14;`). parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>>411 fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> { 412 let eq_consumed = match self.token.kind { 413 token::BinOpEq(..) => { 414 // Recover `let x <op>= 1` as `let x = 1` 415 self.sess 416 .emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span }); 417 self.bump(); 418 true 419 } 420 _ => self.eat(&token::Eq), 421 }; 422 423 Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None }) 424 } 425 426 /// Parses a block. No inner attributes are allowed. parse_block(&mut self) -> PResult<'a, P<Block>>427 pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> { 428 let (attrs, block) = self.parse_inner_attrs_and_block()?; 429 if let [.., last] = &*attrs { 430 self.error_on_forbidden_inner_attr( 431 last.span, 432 super::attr::InnerAttrPolicy::Forbidden(Some( 433 InnerAttrForbiddenReason::InCodeBlock, 434 )), 435 ); 436 } 437 Ok(block) 438 } 439 error_block_no_opening_brace_msg( &mut self, msg: Cow<'static, str>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed>440 fn error_block_no_opening_brace_msg( 441 &mut self, 442 msg: Cow<'static, str>, 443 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { 444 let sp = self.token.span; 445 let mut e = self.struct_span_err(sp, msg); 446 let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; 447 448 // Check to see if the user has written something like 449 // 450 // if (cond) 451 // bar; 452 // 453 // which is valid in other languages, but not Rust. 454 match self.parse_stmt_without_recovery(false, ForceCollect::No) { 455 // If the next token is an open brace, e.g., we have: 456 // 457 // if expr other_expr { 458 // ^ ^ ^- lookahead(1) is a brace 459 // | |- current token is not "else" 460 // |- (statement we just parsed) 461 // 462 // the place-inside-a-block suggestion would be more likely wrong than right. 463 // 464 // FIXME(compiler-errors): this should probably parse an arbitrary expr and not 465 // just lookahead one token, so we can see if there's a brace after _that_, 466 // since we want to protect against: 467 // `if 1 1 + 1 {` being suggested as `if { 1 } 1 + 1 {` 468 // + + 469 Ok(Some(_)) 470 if (!self.token.is_keyword(kw::Else) 471 && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))) 472 || do_not_suggest_help => {} 473 // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836). 474 Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {} 475 Ok(Some(stmt)) => { 476 let stmt_own_line = self.sess.source_map().is_line_before_span_empty(sp); 477 let stmt_span = if stmt_own_line && self.eat(&token::Semi) { 478 // Expand the span to include the semicolon. 479 stmt.span.with_hi(self.prev_token.span.hi()) 480 } else { 481 stmt.span 482 }; 483 e.multipart_suggestion( 484 "try placing this code inside a block", 485 vec![ 486 (stmt_span.shrink_to_lo(), "{ ".to_string()), 487 (stmt_span.shrink_to_hi(), " }".to_string()), 488 ], 489 // Speculative; has been misleading in the past (#46836). 490 Applicability::MaybeIncorrect, 491 ); 492 } 493 Err(e) => { 494 self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); 495 e.cancel(); 496 } 497 _ => {} 498 } 499 e.span_label(sp, "expected `{`"); 500 e 501 } 502 error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T>503 fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { 504 let tok = super::token_descr(&self.token); 505 let msg = format!("expected `{{`, found {}", tok); 506 Err(self.error_block_no_opening_brace_msg(Cow::from(msg))) 507 } 508 509 /// Parses a block. Inner attributes are allowed. parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)>510 pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> { 511 self.parse_block_common(self.token.span, BlockCheckMode::Default, true) 512 } 513 514 /// Parses a block. Inner attributes are allowed. parse_block_common( &mut self, lo: Span, blk_mode: BlockCheckMode, can_be_struct_literal: bool, ) -> PResult<'a, (AttrVec, P<Block>)>515 pub(super) fn parse_block_common( 516 &mut self, 517 lo: Span, 518 blk_mode: BlockCheckMode, 519 can_be_struct_literal: bool, 520 ) -> PResult<'a, (AttrVec, P<Block>)> { 521 maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x)); 522 523 let maybe_ident = self.prev_token.clone(); 524 self.maybe_recover_unexpected_block_label(); 525 if !self.eat(&token::OpenDelim(Delimiter::Brace)) { 526 return self.error_block_no_opening_brace(); 527 } 528 529 let attrs = self.parse_inner_attributes()?; 530 let tail = match self.maybe_suggest_struct_literal( 531 lo, 532 blk_mode, 533 maybe_ident, 534 can_be_struct_literal, 535 ) { 536 Some(tail) => tail?, 537 None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, 538 }; 539 Ok((attrs, tail)) 540 } 541 542 /// Parses the rest of a block expression or function body. 543 /// Precondition: already parsed the '{'. parse_block_tail( &mut self, lo: Span, s: BlockCheckMode, recover: AttemptLocalParseRecovery, ) -> PResult<'a, P<Block>>544 pub(crate) fn parse_block_tail( 545 &mut self, 546 lo: Span, 547 s: BlockCheckMode, 548 recover: AttemptLocalParseRecovery, 549 ) -> PResult<'a, P<Block>> { 550 let mut stmts = ThinVec::new(); 551 let mut snapshot = None; 552 while !self.eat(&token::CloseDelim(Delimiter::Brace)) { 553 if self.token == token::Eof { 554 break; 555 } 556 if self.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) { 557 // Account for `<<<<<<<` diff markers. We can't proactively error here because 558 // that can be a valid path start, so we snapshot and reparse only we've 559 // encountered another parse error. 560 snapshot = Some(self.create_snapshot_for_diagnostic()); 561 } 562 let stmt = match self.parse_full_stmt(recover) { 563 Err(mut err) if recover.yes() => { 564 if let Some(ref mut snapshot) = snapshot { 565 snapshot.recover_diff_marker(); 566 } 567 if self.token == token::Colon { 568 // if next token is following a colon, it's likely a path 569 // and we can suggest a path separator 570 self.bump(); 571 if self.token.span.lo() == self.prev_token.span.hi() { 572 err.span_suggestion_verbose( 573 self.prev_token.span, 574 "maybe write a path separator here", 575 "::", 576 Applicability::MaybeIncorrect, 577 ); 578 } 579 if self.sess.unstable_features.is_nightly_build() { 580 // FIXME(Nilstrieb): Remove this again after a few months. 581 err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>"); 582 } 583 } 584 585 err.emit(); 586 self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); 587 Some(self.mk_stmt_err(self.token.span)) 588 } 589 Ok(stmt) => stmt, 590 Err(err) => return Err(err), 591 }; 592 if let Some(stmt) = stmt { 593 stmts.push(stmt); 594 } else { 595 // Found only `;` or `}`. 596 continue; 597 }; 598 } 599 Ok(self.mk_block(stmts, s, lo.to(self.prev_token.span))) 600 } 601 602 /// Parses a statement, including the trailing semicolon. parse_full_stmt( &mut self, recover: AttemptLocalParseRecovery, ) -> PResult<'a, Option<Stmt>>603 pub fn parse_full_stmt( 604 &mut self, 605 recover: AttemptLocalParseRecovery, 606 ) -> PResult<'a, Option<Stmt>> { 607 // Skip looking for a trailing semicolon when we have an interpolated statement. 608 maybe_whole!(self, NtStmt, |x| Some(x.into_inner())); 609 610 let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No)? else { 611 return Ok(None); 612 }; 613 614 let mut eat_semi = true; 615 let mut add_semi_to_stmt = false; 616 617 match &mut stmt.kind { 618 // Expression without semicolon. 619 StmtKind::Expr(expr) 620 if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { 621 // Just check for errors and recover; do not eat semicolon yet. 622 // `expect_one_of` returns PResult<'a, bool /* recovered */> 623 624 let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]); 625 626 let replace_with_err = 'break_recover: { 627 match expect_result { 628 // Recover from parser, skip type error to avoid extra errors. 629 Ok(true) => true, 630 Err(mut e) => { 631 if let TokenKind::DocComment(..) = self.token.kind 632 && let Ok(snippet) = self.span_to_snippet(self.token.span) 633 { 634 let sp = self.token.span; 635 let marker = &snippet[..3]; 636 let (comment_marker, doc_comment_marker) = marker.split_at(2); 637 638 e.span_suggestion( 639 sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), 640 format!( 641 "add a space before `{}` to use a regular comment", 642 doc_comment_marker, 643 ), 644 format!("{} {}", comment_marker, doc_comment_marker), 645 Applicability::MaybeIncorrect, 646 ); 647 } 648 649 if self.recover_colon_as_semi() { 650 // recover_colon_as_semi has already emitted a nicer error. 651 e.delay_as_bug(); 652 add_semi_to_stmt = true; 653 eat_semi = false; 654 655 break 'break_recover false; 656 } 657 658 match &expr.kind { 659 ExprKind::Path(None, ast::Path { segments, .. }) if segments.len() == 1 => { 660 if self.token == token::Colon 661 && self.look_ahead(1, |token| { 662 token.is_whole_block() || matches!( 663 token.kind, 664 token::Ident(kw::For | kw::Loop | kw::While, false) 665 | token::OpenDelim(Delimiter::Brace) 666 ) 667 }) 668 { 669 let snapshot = self.create_snapshot_for_diagnostic(); 670 let label = Label { 671 ident: Ident::from_str_and_span( 672 &format!("'{}", segments[0].ident), 673 segments[0].ident.span, 674 ), 675 }; 676 match self.parse_expr_labeled(label, false) { 677 Ok(labeled_expr) => { 678 e.delay_as_bug(); 679 self.sess.emit_err(MalformedLoopLabel { 680 span: label.ident.span, 681 correct_label: label.ident, 682 }); 683 *expr = labeled_expr; 684 break 'break_recover false; 685 } 686 Err(err) => { 687 err.cancel(); 688 self.restore_snapshot(snapshot); 689 } 690 } 691 } 692 } 693 _ => {} 694 } 695 696 if let Err(mut e) = 697 self.check_mistyped_turbofish_with_multiple_type_params(e, expr) 698 { 699 if recover.no() { 700 return Err(e); 701 } 702 e.emit(); 703 self.recover_stmt(); 704 } 705 706 true 707 708 } 709 Ok(false) => false 710 } 711 }; 712 713 if replace_with_err { 714 // We already emitted an error, so don't emit another type error 715 let sp = expr.span.to(self.prev_token.span); 716 *expr = self.mk_expr_err(sp); 717 } 718 } 719 StmtKind::Expr(_) | StmtKind::MacCall(_) => {} 720 StmtKind::Local(local) if let Err(e) = self.expect_semi() => { 721 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover. 722 match &mut local.kind { 723 LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => { 724 self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; 725 // We found `foo<bar, baz>`, have we fully recovered? 726 self.expect_semi()?; 727 } 728 LocalKind::Decl => return Err(e), 729 } 730 eat_semi = false; 731 } 732 StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => eat_semi = false, 733 } 734 735 if add_semi_to_stmt || (eat_semi && self.eat(&token::Semi)) { 736 stmt = stmt.add_trailing_semicolon(); 737 } 738 739 stmt.span = stmt.span.to(self.prev_token.span); 740 Ok(Some(stmt)) 741 } 742 mk_block( &self, stmts: ThinVec<Stmt>, rules: BlockCheckMode, span: Span, ) -> P<Block>743 pub(super) fn mk_block( 744 &self, 745 stmts: ThinVec<Stmt>, 746 rules: BlockCheckMode, 747 span: Span, 748 ) -> P<Block> { 749 P(Block { 750 stmts, 751 id: DUMMY_NODE_ID, 752 rules, 753 span, 754 tokens: None, 755 could_be_bare_literal: false, 756 }) 757 } 758 mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt759 pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { 760 Stmt { id: DUMMY_NODE_ID, kind, span } 761 } 762 mk_stmt_err(&self, span: Span) -> Stmt763 pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt { 764 self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span))) 765 } 766 mk_block_err(&self, span: Span) -> P<Block>767 pub(super) fn mk_block_err(&self, span: Span) -> P<Block> { 768 self.mk_block(thin_vec![self.mk_stmt_err(span)], BlockCheckMode::Default, span) 769 } 770 } 771