From d763faf92198e3f0c851388c71d2bb8a2f04afd9 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 15 May 2019 19:47:18 -0700 Subject: Parse alternative incorrect uses of await and recover --- src/libsyntax/parse/parser.rs | 113 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 8 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 99e8db9d8e6..55e13ef00dc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2629,14 +2629,94 @@ impl<'a> Parser<'a> { db.note("variable declaration using `let` is a statement"); return Err(db); } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) { - // FIXME: remove this branch when `await!` is no longer supported - // https://github.com/rust-lang/rust/issues/60610 - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - hi = self.prev_span; - ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr); + let await_sp = self.prev_span; + match self.token { + token::Not => { + // FIXME: make this an error when `await!` is no longer supported + // https://github.com/rust-lang/rust/issues/60610 + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr().map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this await macro call", + ); + err + })?; + self.expect(&token::CloseDelim(token::Paren))?; + ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr); + } + token::Question => { + // Handle `await? ` + self.bump(); // `?` + let expr = self.parse_expr().map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this incorrect await statement", + ); + err + })?; + let sp = lo.to(expr.span); + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let expr = self.mk_expr( + sp, + ExprKind::Await(ast::AwaitOrigin::FieldLike, expr), + ThinVec::new(), + ); + hi = sp; + ex = ExprKind::Try(expr); + let mut err = self.struct_span_err( + await_sp, + "incorrect use of `await`", + ); + err.span_suggestion( + sp, + "`await` is not a statement", + format!("{}.await?", expr_str), + Applicability::MachineApplicable, + ); + err.emit(); + } + ref t => { + // Handle `await ` + let expr = if t == &token::OpenDelim(token::Brace) { + // Handle `await { }` + // this needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await` + self.parse_block_expr( + None, + self.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this incorrect await statement", + ); + err + })?; + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let sp = lo.to(expr.span); + hi = sp; + ex = ExprKind::Await(ast::AwaitOrigin::FieldLike, expr); + let mut err = self.struct_span_err( + await_sp, + "incorrect use of `await`", + ); + err.span_suggestion( + sp, + "`await` is not a statement", + format!("{}.await", expr_str), + Applicability::MachineApplicable, + ); + err.emit(); + } + } } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Expr)?; @@ -2913,6 +2993,23 @@ impl<'a> Parser<'a> { ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg), ThinVec::new(), ); + if self.token == token::OpenDelim(token::Paren) && + self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) + { + // future.await() + let lo = self.span; + self.bump(); // ( + let sp = lo.to(self.span); + self.bump(); // ) + let mut err = self.struct_span_err(span, "incorrect use of `await`"); + err.span_suggestion( + sp, + "`await` is not a method call, remove the parentheses", + String::new(), + Applicability::MachineApplicable, + ); + err.emit() + } return Ok(await_expr); } let segment = self.parse_path_segment(PathStyle::Expr)?; -- cgit 1.4.1-3-g733a5 From ee02661474abad0c91b8031c920904ab14f30c7e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 15 May 2019 19:59:56 -0700 Subject: Split parser logic to its own method --- src/libsyntax/parse/parser.rs | 183 ++++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 87 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 55e13ef00dc..83bfd93d066 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2630,93 +2630,9 @@ impl<'a> Parser<'a> { return Err(db); } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) { let await_sp = self.prev_span; - match self.token { - token::Not => { - // FIXME: make this an error when `await!` is no longer supported - // https://github.com/rust-lang/rust/issues/60610 - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr().map_err(|mut err| { - err.span_label( - await_sp, - "while parsing this await macro call", - ); - err - })?; - self.expect(&token::CloseDelim(token::Paren))?; - ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr); - } - token::Question => { - // Handle `await? ` - self.bump(); // `?` - let expr = self.parse_expr().map_err(|mut err| { - err.span_label( - await_sp, - "while parsing this incorrect await statement", - ); - err - })?; - let sp = lo.to(expr.span); - let expr_str = self.sess.source_map().span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - let expr = self.mk_expr( - sp, - ExprKind::Await(ast::AwaitOrigin::FieldLike, expr), - ThinVec::new(), - ); - hi = sp; - ex = ExprKind::Try(expr); - let mut err = self.struct_span_err( - await_sp, - "incorrect use of `await`", - ); - err.span_suggestion( - sp, - "`await` is not a statement", - format!("{}.await?", expr_str), - Applicability::MachineApplicable, - ); - err.emit(); - } - ref t => { - // Handle `await ` - let expr = if t == &token::OpenDelim(token::Brace) { - // Handle `await { }` - // this needs to be handled separatedly from the next arm to avoid - // interpreting `await { }?` as `?.await` - self.parse_block_expr( - None, - self.span, - BlockCheckMode::Default, - ThinVec::new(), - ) - } else { - self.parse_expr() - }.map_err(|mut err| { - err.span_label( - await_sp, - "while parsing this incorrect await statement", - ); - err - })?; - let expr_str = self.sess.source_map().span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - let sp = lo.to(expr.span); - hi = sp; - ex = ExprKind::Await(ast::AwaitOrigin::FieldLike, expr); - let mut err = self.struct_span_err( - await_sp, - "incorrect use of `await`", - ); - err.span_suggestion( - sp, - "`await` is not a statement", - format!("{}.await", expr_str), - Applicability::MachineApplicable, - ); - err.emit(); - } - } + let e = self.parse_async_macro_or_stmt(lo, await_sp)?; + hi = e.0; + ex = e.1; } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Expr)?; @@ -2781,6 +2697,99 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + fn parse_async_macro_or_stmt( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + Ok(match self.token { + token::Not => { + // Handle correct `await!()` + // FIXME: make this an error when `await!` is no longer supported + // https://github.com/rust-lang/rust/issues/60610 + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr().map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this await macro call", + ); + err + })?; + self.expect(&token::CloseDelim(token::Paren))?; + (expr.span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr)) + } + token::Question => { + // Handle `await? ` + self.bump(); // `?` + let expr = self.parse_expr().map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this incorrect await statement", + ); + err + })?; + let sp = lo.to(expr.span); + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let expr = self.mk_expr( + sp, + ExprKind::Await(ast::AwaitOrigin::FieldLike, expr), + ThinVec::new(), + ); + let mut err = self.struct_span_err( + await_sp, + "incorrect use of `await`", + ); + err.span_suggestion( + sp, + "`await` is not a statement", + format!("{}.await?", expr_str), + Applicability::MachineApplicable, + ); + err.emit(); + (sp, ExprKind::Try(expr)) + } + ref t => { + // Handle `await ` + let expr = if t == &token::OpenDelim(token::Brace) { + // Handle `await { }` + // this needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await` + self.parse_block_expr( + None, + self.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this incorrect await statement", + ); + err + })?; + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let sp = lo.to(expr.span); + let mut err = self.struct_span_err( + await_sp, + "incorrect use of `await`", + ); + err.span_suggestion( + sp, + "`await` is not a statement", + format!("{}.await", expr_str), + Applicability::MachineApplicable, + ); + err.emit(); + (sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)) + } + }) + } + fn maybe_parse_struct_expr( &mut self, lo: Span, -- cgit 1.4.1-3-g733a5 From 01c6689604d671c5fa51671940f69833222194ef Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 15 May 2019 20:06:15 -0700 Subject: Simplify span usage for incorrect await --- src/libsyntax/parse/parser.rs | 6 +-- .../incorrect-syntax-suggestions.stderr | 60 +++++++--------------- src/test/ui/feature-gate/await-macro.stderr | 2 +- 3 files changed, 23 insertions(+), 45 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 83bfd93d066..45081aadfd9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2738,7 +2738,7 @@ impl<'a> Parser<'a> { ThinVec::new(), ); let mut err = self.struct_span_err( - await_sp, + sp, "incorrect use of `await`", ); err.span_suggestion( @@ -2775,7 +2775,7 @@ impl<'a> Parser<'a> { .unwrap_or_else(|_| pprust::expr_to_string(&expr)); let sp = lo.to(expr.span); let mut err = self.struct_span_err( - await_sp, + sp, "incorrect use of `await`", ); err.span_suggestion( @@ -3010,7 +3010,7 @@ impl<'a> Parser<'a> { self.bump(); // ( let sp = lo.to(self.span); self.bump(); // ) - let mut err = self.struct_span_err(span, "incorrect use of `await`"); + let mut err = self.struct_span_err(sp, "incorrect use of `await`"); err.span_suggestion( sp, "`await` is not a method call, remove the parentheses", diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr index f39ccfcc95c..2e2efedcf00 100644 --- a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr @@ -2,113 +2,91 @@ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:10:13 | LL | let _ = await bar(); - | ^^^^^------ - | | - | help: `await` is not a statement: `bar().await` + | ^^^^^^^^^^^ help: `await` is not a statement: `bar().await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:14:13 | LL | let _ = await? bar(); - | ^^^^^------- - | | - | help: `await` is not a statement: `bar().await?` + | ^^^^^^^^^^^^ help: `await` is not a statement: `bar().await?` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:18:13 | LL | let _ = await bar()?; - | ^^^^^------- - | | - | help: `await` is not a statement: `bar()?.await` + | ^^^^^^^^^^^^ help: `await` is not a statement: `bar()?.await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:23:13 | LL | let _ = await { bar() }; - | ^^^^^---------- - | | - | help: `await` is not a statement: `{ bar() }.await` + | ^^^^^^^^^^^^^^^ help: `await` is not a statement: `{ bar() }.await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:27:13 | LL | let _ = await(bar()); - | ^^^^^------- - | | - | help: `await` is not a statement: `(bar()).await` + | ^^^^^^^^^^^^ help: `await` is not a statement: `(bar()).await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:31:13 | LL | let _ = await { bar() }?; - | ^^^^^---------- - | | - | help: `await` is not a statement: `{ bar() }.await` + | ^^^^^^^^^^^^^^^ help: `await` is not a statement: `{ bar() }.await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:35:14 | LL | let _ = (await bar())?; - | ^^^^^------ - | | - | help: `await` is not a statement: `bar().await` + | ^^^^^^^^^^^ help: `await` is not a statement: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:39:13 + --> $DIR/incorrect-syntax-suggestions.rs:39:24 | LL | let _ = bar().await(); - | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:43:13 + --> $DIR/incorrect-syntax-suggestions.rs:43:24 | LL | let _ = bar().await()?; - | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:55:13 | LL | let _ = await bar(); - | ^^^^^------ - | | - | help: `await` is not a statement: `bar().await` + | ^^^^^^^^^^^ help: `await` is not a statement: `bar().await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:60:13 | LL | let _ = await? bar(); - | ^^^^^------- - | | - | help: `await` is not a statement: `bar().await?` + | ^^^^^^^^^^^^ help: `await` is not a statement: `bar().await?` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:65:13 | LL | let _ = await bar()?; - | ^^^^^------- - | | - | help: `await` is not a statement: `bar()?.await` + | ^^^^^^^^^^^^ help: `await` is not a statement: `bar()?.await` error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:70:14 | LL | let _ = (await bar())?; - | ^^^^^------ - | | - | help: `await` is not a statement: `bar().await` + | ^^^^^^^^^^^ help: `await` is not a statement: `bar().await` error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:75:13 + --> $DIR/incorrect-syntax-suggestions.rs:75:24 | LL | let _ = bar().await(); - | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + | ^^ help: `await` is not a method call, remove the parentheses error: incorrect use of `await` - --> $DIR/incorrect-syntax-suggestions.rs:80:13 + --> $DIR/incorrect-syntax-suggestions.rs:80:24 | LL | let _ = bar().await()?; - | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + | ^^ help: `await` is not a method call, remove the parentheses error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:55:13 diff --git a/src/test/ui/feature-gate/await-macro.stderr b/src/test/ui/feature-gate/await-macro.stderr index 699a7a8886e..57aab6800f7 100644 --- a/src/test/ui/feature-gate/await-macro.stderr +++ b/src/test/ui/feature-gate/await-macro.stderr @@ -2,7 +2,7 @@ error[E0658]: `await!()` macro syntax is unstable, and will soon be remove --> $DIR/await-macro.rs:9:5 | LL | await!(bar()); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(await_macro)] to the crate attributes to enable -- cgit 1.4.1-3-g733a5 From b9d6fe3ae96a7f1f478dc6baf29b8e4cff5ab865 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 16 May 2019 13:33:26 -0700 Subject: Review comments - Change wording of suggestion - Move recovery logic to `diagnostics.rs` - Reduce ammount of code duplication --- src/libsyntax/parse/diagnostics.rs | 40 ++++++- src/libsyntax/parse/parser.rs | 124 +++++---------------- .../incorrect-syntax-suggestions.stderr | 26 ++--- 3 files changed, 81 insertions(+), 109 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 32e1ee94f0d..61453e35095 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,5 +1,5 @@ use crate::ast; -use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind}; +use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind}; use crate::parse::parser::PathStyle; use crate::parse::token; use crate::parse::PResult; @@ -223,4 +223,42 @@ impl<'a> Parser<'a> { false } } + + /// Consume alternative await syntaxes like `await `, `await? `, `await()` + /// and `await { }`. + crate fn parse_incorrect_await_syntax( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + let is_question = self.eat(&token::Question); // Handle `await? `. + let expr = if self.token == token::OpenDelim(token::Brace) { + // Handle `await { }`. + // This needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await`. + self.parse_block_expr( + None, + self.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label(await_sp, "while parsing this incorrect await expression"); + err + })?; + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); + let sp = lo.to(expr.span); + let app = match expr.node { + ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` + _ => Applicability::MachineApplicable, + }; + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) + .emit(); + Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr))) + } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 45081aadfd9..bb0f9fa9502 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2629,10 +2629,9 @@ impl<'a> Parser<'a> { db.note("variable declaration using `let` is a statement"); return Err(db); } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) { - let await_sp = self.prev_span; - let e = self.parse_async_macro_or_stmt(lo, await_sp)?; - hi = e.0; - ex = e.1; + let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?; + hi = await_hi; + ex = e_kind; } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Expr)?; @@ -2697,97 +2696,29 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_async_macro_or_stmt( + /// Parse `await!()` calls, or alternatively recover from incorrect but reasonable + /// alternative syntaxes `await `, `await? `, `await()` and + /// `await { }`. + fn parse_await_macro_or_alt( &mut self, lo: Span, await_sp: Span, ) -> PResult<'a, (Span, ExprKind)> { - Ok(match self.token { - token::Not => { - // Handle correct `await!()` - // FIXME: make this an error when `await!` is no longer supported - // https://github.com/rust-lang/rust/issues/60610 - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr().map_err(|mut err| { - err.span_label( - await_sp, - "while parsing this await macro call", - ); - err - })?; - self.expect(&token::CloseDelim(token::Paren))?; - (expr.span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr)) - } - token::Question => { - // Handle `await? ` - self.bump(); // `?` - let expr = self.parse_expr().map_err(|mut err| { - err.span_label( - await_sp, - "while parsing this incorrect await statement", - ); - err - })?; - let sp = lo.to(expr.span); - let expr_str = self.sess.source_map().span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - let expr = self.mk_expr( - sp, - ExprKind::Await(ast::AwaitOrigin::FieldLike, expr), - ThinVec::new(), - ); - let mut err = self.struct_span_err( - sp, - "incorrect use of `await`", - ); - err.span_suggestion( - sp, - "`await` is not a statement", - format!("{}.await?", expr_str), - Applicability::MachineApplicable, - ); - err.emit(); - (sp, ExprKind::Try(expr)) - } - ref t => { - // Handle `await ` - let expr = if t == &token::OpenDelim(token::Brace) { - // Handle `await { }` - // this needs to be handled separatedly from the next arm to avoid - // interpreting `await { }?` as `?.await` - self.parse_block_expr( - None, - self.span, - BlockCheckMode::Default, - ThinVec::new(), - ) - } else { - self.parse_expr() - }.map_err(|mut err| { - err.span_label( - await_sp, - "while parsing this incorrect await statement", - ); - err - })?; - let expr_str = self.sess.source_map().span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - let sp = lo.to(expr.span); - let mut err = self.struct_span_err( - sp, - "incorrect use of `await`", - ); - err.span_suggestion( - sp, - "`await` is not a statement", - format!("{}.await", expr_str), - Applicability::MachineApplicable, - ); - err.emit(); - (sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)) - } - }) + if self.token == token::Not { + // Handle correct `await!()`. + // FIXME: make this an error when `await!` is no longer supported + // https://github.com/rust-lang/rust/issues/60610 + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr().map_err(|mut err| { + err.span_label(await_sp, "while parsing this await macro call"); + err + })?; + self.expect(&token::CloseDelim(token::Paren))?; + Ok((expr.span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr))) + } else { // Handle `await `. + self.parse_incorrect_await_syntax(lo, await_sp) + } } fn maybe_parse_struct_expr( @@ -2938,10 +2869,13 @@ impl<'a> Parser<'a> { } /// Parses a block or unsafe block. - fn parse_block_expr(&mut self, opt_label: Option