From 08cd34e4fc062345dd20c018384b360cd57915b1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 9 May 2019 15:37:37 -0700 Subject: [PATCH 01/17] Switch to SPDX 2.1 license expression According to the Cargo Reference: https://doc.rust-lang.org/cargo/reference/manifest.html > This is an SPDX 2.1 license expression for this package. Currently > crates.io will validate the license provided against a whitelist of > known license and exception identifiers from the SPDX license list > 2.4. Parentheses are not currently supported. > > Multiple licenses can be separated with a `/`, although that usage > is deprecated. Instead, use a license expression with AND and OR > operators to get more explicit semantics. --- src/libstd/Cargo.toml | 2 +- src/tools/rustbook/Cargo.toml | 2 +- src/tools/rustc-std-workspace-alloc/Cargo.toml | 2 +- src/tools/rustc-std-workspace-core/Cargo.toml | 2 +- src/tools/rustc-workspace-hack/Cargo.toml | 2 +- src/tools/unstable-book-gen/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index ad5d62f667ac9..5d797b756213d 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -3,7 +3,7 @@ authors = ["The Rust Project Developers"] name = "std" version = "0.0.0" build = "build.rs" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "The Rust Standard Library" edition = "2018" diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 5bf1553b22711..d2b1a7bac60ae 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -2,7 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustbook" version = "0.1.0" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] diff --git a/src/tools/rustc-std-workspace-alloc/Cargo.toml b/src/tools/rustc-std-workspace-alloc/Cargo.toml index 98578914963db..05df1fddc7f1c 100644 --- a/src/tools/rustc-std-workspace-alloc/Cargo.toml +++ b/src/tools/rustc-std-workspace-alloc/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc-std-workspace-alloc" version = "1.0.0" authors = ["Alex Crichton "] -license = 'MIT/Apache-2.0' +license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ diff --git a/src/tools/rustc-std-workspace-core/Cargo.toml b/src/tools/rustc-std-workspace-core/Cargo.toml index d527ce12bc3a1..38ca56a557be6 100644 --- a/src/tools/rustc-std-workspace-core/Cargo.toml +++ b/src/tools/rustc-std-workspace-core/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc-std-workspace-core" version = "1.0.0" authors = ["Alex Crichton "] -license = 'MIT/Apache-2.0' +license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index d51841cd65075..290c4481c005e 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc-workspace-hack" version = "1.0.0" authors = ["Alex Crichton "] -license = 'MIT/Apache-2.0' +license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml index 3209de09aeb68..e43e4e6c7cb5a 100644 --- a/src/tools/unstable-book-gen/Cargo.toml +++ b/src/tools/unstable-book-gen/Cargo.toml @@ -3,7 +3,7 @@ authors = ["est31 ", "The Rust Project Developers"] name = "unstable-book-gen" version = "0.1.0" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] From 7c55b48d3121178ca05e04812e4c708f7fa6dff5 Mon Sep 17 00:00:00 2001 From: MaulingMonkey Date: Thu, 9 May 2019 16:15:43 -0700 Subject: [PATCH 02/17] Fix .natvis visualizers. Updated to handle these changes: - `core::ptr::*` lost their `__0` elements and are just plain pointers - `core::ptr::*` probably shouldn't dereference in `DisplayString` s - `VecDeque` and `Vec` use `core::ptr::*` s - `VecDeque` and `LinkedList` moved modules again. Retested - still working fine, left alone: - `String`, `&str`, `Option` --- src/etc/natvis/liballoc.natvis | 12 ++++++------ src/etc/natvis/libcore.natvis | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index e3d99e34b3579..de30b58526a13 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -7,11 +7,11 @@ buf.cap len - buf.ptr.pointer.__0 + buf.ptr.pointer - + {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} tail <= head ? head - tail : buf.cap - tail + head @@ -24,19 +24,19 @@ - buf.ptr.pointer.__0 + i + buf.ptr.pointer[i] i = (i + 1 == buf.cap ? 0 : i + 1) - + {{ size={len} }} len - *(alloc::linked_list::Node<$T1> **)&head - *(alloc::linked_list::Node<$T1> **)&next + *(alloc::collections::linked_list::Node<$T1> **)&head + *(alloc::collections::linked_list::Node<$T1> **)&next element diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 37d64be1ce963..0e703b3b95026 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -1,15 +1,15 @@ - {{ Unique {*pointer.__0} }} + {{ Unique {pointer} }} - pointer.__0 + pointer - {{ Shared {*pointer.__0} }} + {{ Shared {pointer} }} - pointer.__0 + pointer From 01bc58c5eecd0ed993ee37993f24c63780082e76 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 13 May 2019 17:42:55 -0400 Subject: [PATCH 03/17] remove compiletest's dependency on `filetime` --- Cargo.lock | 1 - src/tools/compiletest/Cargo.toml | 1 - src/tools/compiletest/src/main.rs | 27 ++++++++++++++++----------- src/tools/compiletest/src/runtest.rs | 3 +-- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 982070a243ee5..b6dc3bdb89bd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,6 @@ version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 336d7e32024b7..e759ad1f35dde 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] diff = "0.1.10" env_logger = { version = "0.5", default-features = false } -filetime = "0.2" getopts = "0.2" log = "0.4" regex = "1.0" diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index e253934e566a7..442e58bfd74e1 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -9,7 +9,6 @@ use crate::common::CompareMode; use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; use crate::common::{Config, TestPaths}; use crate::common::{DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Mode, Pretty}; -use filetime::FileTime; use getopts::Options; use std::env; use std::ffi::OsString; @@ -17,6 +16,7 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::Command; +use std::time::SystemTime; use test::ColorConfig; use crate::util::logv; use walkdir::WalkDir; @@ -752,31 +752,36 @@ fn up_to_date( #[derive(Debug, PartialEq, PartialOrd, Ord, Eq)] struct Stamp { - time: FileTime, + time: SystemTime, file: PathBuf, } impl Stamp { fn from_path(p: &Path) -> Self { + let time = fs::metadata(p) + .and_then(|metadata| metadata.modified()) + .unwrap_or(SystemTime::UNIX_EPOCH); + Stamp { - time: mtime(&p), + time, file: p.into(), } } - fn from_dir(path: &Path) -> impl Iterator { + fn from_dir(path: &Path) -> impl Iterator { WalkDir::new(path) .into_iter() .map(|entry| entry.unwrap()) .filter(|entry| entry.file_type().is_file()) - .map(|entry| Stamp::from_path(entry.path())) - } -} + .map(|entry| { + let time = (|| -> io::Result<_> { entry.metadata()?.modified() })(); -fn mtime(path: &Path) -> FileTime { - fs::metadata(path) - .map(|f| FileTime::from_last_modification_time(&f)) - .unwrap_or_else(|_| FileTime::zero()) + Stamp { + time: time.unwrap_or(SystemTime::UNIX_EPOCH), + file: entry.path().into(), + } + }) + } } fn make_test_name( diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 10b8133326bba..22c2f0a05379b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -9,7 +9,6 @@ use crate::common::{Config, TestPaths}; use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly}; use diff; use crate::errors::{self, Error, ErrorKind}; -use filetime::FileTime; use crate::header::TestProps; use crate::json; use regex::{Captures, Regex}; @@ -3032,7 +3031,7 @@ impl<'test> TestCx<'test> { } fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) { - let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap()); + let t = |file| fs::metadata(file).unwrap().modified().unwrap(); let source_file = &self.testpaths.file; let output_time = t(output_file); let source_time = t(source_file); From 6d207f53a4ea28151233a49f3f52fd051d0d6d21 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 15 May 2019 21:24:18 +0200 Subject: [PATCH 04/17] Get ty from local_decls instead of using Place --- src/librustc_codegen_ssa/mir/analyze.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 8021d4b11d0cf..06d7b6c78f14b 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -243,9 +243,8 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> } PlaceContext::MutatingUse(MutatingUseContext::Drop) => { - let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir, - self.fx.cx.tcx()); - let ty = self.fx.monomorphize(&ty.ty); + let ty = self.fx.mir.local_decls[local].ty; + let ty = self.fx.monomorphize(&ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { From d763faf92198e3f0c851388c71d2bb8a2f04afd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 May 2019 19:47:18 -0700 Subject: [PATCH 05/17] Parse alternative incorrect uses of await and recover --- src/librustc/hir/lowering.rs | 19 +- src/libsyntax/parse/parser.rs | 113 +++++++++- ...018-edition-error-in-non-macro-position.rs | 4 +- ...edition-error-in-non-macro-position.stderr | 10 +- .../ui/await-keyword/2018-edition-error.rs | 4 +- .../await-keyword/2018-edition-error.stderr | 10 +- .../incorrect-syntax-suggestions.rs | 93 +++++++++ .../incorrect-syntax-suggestions.stderr | 196 ++++++++++++++++++ .../await-keyword/post_expansion_error.stderr | 4 +- src/test/ui/issues/issue-51719.rs | 2 + src/test/ui/issues/issue-51719.stderr | 5 +- src/test/ui/issues/issue-51751.stderr | 5 +- 12 files changed, 428 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/await-keyword/incorrect-syntax-suggestions.rs create mode 100644 src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd0d13d8f5a6a..12ccc79e4ab41 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -97,6 +97,10 @@ pub struct LoweringContext<'a> { is_generator: bool, is_async_body: bool, + /// Used to get the current `fn`'s def span to point to when using `await` + /// outside of an `async fn`. + current_item_id: Option, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -250,6 +254,7 @@ pub fn lower_crate( node_id_to_hir_id: IndexVec::new(), is_generator: false, is_async_body: false, + current_item_id: None, is_in_trait_impl: false, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, @@ -3115,6 +3120,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, ref header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); + let hir_id = self.lower_node_id(id); self.with_new_scopes(|this| { let mut lower_fn = |decl: &FnDecl| { // Note: we don't need to change the return type from `T` to @@ -3153,6 +3159,7 @@ impl<'a> LoweringContext<'a> { } else { lower_fn(decl) }; + this.current_item_id = Some(hir_id); hir::ItemKind::Fn( fn_decl, @@ -5551,13 +5558,21 @@ impl<'a> LoweringContext<'a> { // } // } if !self.is_async_body { - span_err!( + let mut err = struct_span_err!( self.sess, await_span, E0728, "`await` is only allowed inside `async` functions and blocks" ); - self.sess.abort_if_errors(); + err.span_label(await_span, "only allowed inside `async` functions and blocks"); + if let Some(item_id) = self.current_item_id { + err.span_label( + self.sess.source_map().def_span(self.items[&item_id].span), + "this function is not `async`", + ); + } + err.emit(); + return hir::ExprKind::Err; } let span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::Await, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 99e8db9d8e6d2..55e13ef00dcc9 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)?; diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs index b2e8e4be17244..f59f1160e703e 100644 --- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs +++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs @@ -22,6 +22,4 @@ macro_rules! await { () => {} } -fn main() { - match await { await => () } //~ ERROR expected `!`, found `{` -} +fn main() {} diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr index 076a31bd9ced6..c4b82b29f0270 100644 --- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr +++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr @@ -68,13 +68,5 @@ help: you can escape reserved keywords to use them as identifiers LL | macro_rules! r#await { | ^^^^^^^ -error: expected `!`, found `{` - --> $DIR/2018-edition-error-in-non-macro-position.rs:26:17 - | -LL | match await { await => () } - | ----- ^ expected `!` - | | - | while parsing this match expression - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs index e0b2962ce9791..d856869684266 100644 --- a/src/test/ui/await-keyword/2018-edition-error.rs +++ b/src/test/ui/await-keyword/2018-edition-error.rs @@ -9,6 +9,4 @@ mod outer_mod { use self::outer_mod::await::await; //~ ERROR expected identifier //~^ ERROR expected identifier, found reserved keyword `await` -fn main() { - match await { await => () } //~ ERROR expected `!`, found `{` -} +fn main() {} diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr index c8bf9b42ca545..8afe5c1a36b36 100644 --- a/src/test/ui/await-keyword/2018-edition-error.stderr +++ b/src/test/ui/await-keyword/2018-edition-error.stderr @@ -38,13 +38,5 @@ help: you can escape reserved keywords to use them as identifiers LL | use self::outer_mod::await::r#await; | ^^^^^^^ -error: expected `!`, found `{` - --> $DIR/2018-edition-error.rs:13:17 - | -LL | match await { await => () } - | ----- ^ expected `!` - | | - | while parsing this match expression - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs new file mode 100644 index 0000000000000..ca3654d3c8785 --- /dev/null +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs @@ -0,0 +1,93 @@ +// edition:2018 + +#![feature(async_await)] + +async fn bar() -> Result<(), ()> { + Ok(()) +} + +async fn foo1() -> Result<(), ()> { + let _ = await bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo2() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo3() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR incorrect use of `await` + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) +} +async fn foo21() -> Result<(), ()> { + let _ = await { bar() }; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo22() -> Result<(), ()> { + let _ = await(bar()); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo23() -> Result<(), ()> { + let _ = await { bar() }?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo4() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo5() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo6() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo7() -> Result<(), ()> { + let _ = bar().await; // OK + Ok(()) +} +async fn foo8() -> Result<(), ()> { + let _ = bar().await?; // OK + Ok(()) +} +fn foo9() -> Result<(), ()> { + let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo10() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo11() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo12() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo13() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo14() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo15() -> Result<(), ()> { + let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} +fn foo16() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr new file mode 100644 index 0000000000000..f39ccfcc95c89 --- /dev/null +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr @@ -0,0 +1,196 @@ +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:10:13 + | +LL | let _ = await bar(); + | ^^^^^------ + | | + | 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?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:18:13 + | +LL | let _ = await bar()?; + | ^^^^^------- + | | + | 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` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:27:13 + | +LL | let _ = await(bar()); + | ^^^^^------- + | | + | 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` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:35:14 + | +LL | let _ = (await bar())?; + | ^^^^^------ + | | + | help: `await` is not a statement: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:39:13 + | +LL | let _ = bar().await(); + | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:43:13 + | +LL | let _ = bar().await()?; + | ^^^^^^^^^^^-- 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` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:60:13 + | +LL | let _ = await? bar(); + | ^^^^^------- + | | + | 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` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:70:14 + | +LL | let _ = (await bar())?; + | ^^^^^------ + | | + | help: `await` is not a statement: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:75:13 + | +LL | let _ = bar().await(); + | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:80:13 + | +LL | let _ = bar().await()?; + | ^^^^^^^^^^^-- 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 + | +LL | async fn foo8() -> Result<(), ()> { + | --------------------------------- this function is not `async` +... +LL | let _ = await bar(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:60:13 + | +LL | fn foo9() -> Result<(), ()> { + | --------------------------- this function is not `async` +... +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:65:13 + | +LL | fn foo10() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:70:14 + | +LL | fn foo11() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:75:13 + | +LL | fn foo12() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:80:13 + | +LL | fn foo13() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await()?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:85:13 + | +LL | fn foo14() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:89:13 + | +LL | fn foo15() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/incorrect-syntax-suggestions.rs:18:19 + | +LL | let _ = await bar()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to 24 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr index 0996c38b3b6c6..4e525974c2c6f 100644 --- a/src/test/ui/await-keyword/post_expansion_error.stderr +++ b/src/test/ui/await-keyword/post_expansion_error.stderr @@ -2,7 +2,9 @@ error: expected expression, found `)` --> $DIR/post_expansion_error.rs:8:12 | LL | await!() - | ^ expected expression + | ----- ^ expected expression + | | + | while parsing this await macro call error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs index 2c02ac01142bb..b2dbadebc7c1e 100644 --- a/src/test/ui/issues/issue-51719.rs +++ b/src/test/ui/issues/issue-51719.rs @@ -9,3 +9,5 @@ async fn foo() {} fn make_generator() { let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks } + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr index 768909b66ec77..cb4a5e9037086 100644 --- a/src/test/ui/issues/issue-51719.stderr +++ b/src/test/ui/issues/issue-51719.stderr @@ -1,8 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51719.rs:10:19 | +LL | async fn foo() {} + | -------------- this function is not `async` +... LL | let _gen = || foo.await; - | ^^^^^^^^^ + | ^^^^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr index 0c4cb034a9381..842b99f16f256 100644 --- a/src/test/ui/issues/issue-51751.stderr +++ b/src/test/ui/issues/issue-51751.stderr @@ -1,8 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51751.rs:11:20 | +LL | async fn inc(limit: i64) -> i64 { + | ------------------------------- this function is not `async` +... LL | let finished = result.await; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error From ee02661474abad0c91b8031c920904ab14f30c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 May 2019 19:59:56 -0700 Subject: [PATCH 06/17] Split parser logic to its own method --- src/libsyntax/parse/parser.rs | 183 ++++++++++++++++++---------------- 1 file changed, 96 insertions(+), 87 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 55e13ef00dcc9..83bfd93d0664a 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, From 01c6689604d671c5fa51671940f69833222194ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 May 2019 20:06:15 -0700 Subject: [PATCH 07/17] 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(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 83bfd93d0664a..45081aadfd97b 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 f39ccfcc95c89..2e2efedcf00a3 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 699a7a8886e89..57aab6800f7ab 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 From 91c36c40bdd68d928f9202077309ae48f575d187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 May 2019 20:37:50 -0700 Subject: [PATCH 08/17] tidy fix --- src/test/ui/issues/issue-51719.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs index b2dbadebc7c1e..5966edd0bf098 100644 --- a/src/test/ui/issues/issue-51719.rs +++ b/src/test/ui/issues/issue-51719.rs @@ -10,4 +10,4 @@ fn make_generator() { let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks } -fn main() {} \ No newline at end of file +fn main() {} From c61660500555c81d6049b7e7b5b502d1bd9df80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 May 2019 13:17:40 -0700 Subject: [PATCH 09/17] Point at enclosing fn/closure when it's not async --- src/librustc/hir/lowering.rs | 16 +++-- .../incorrect-syntax-suggestions.rs | 14 +++++ .../incorrect-syntax-suggestions.stderr | 58 +++++++++++-------- src/test/ui/issues/issue-51719.stderr | 7 +-- src/test/ui/issues/issue-51751.stderr | 6 +- 5 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 12ccc79e4ab41..3a8b139236cca 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -99,7 +99,7 @@ pub struct LoweringContext<'a> { /// Used to get the current `fn`'s def span to point to when using `await` /// outside of an `async fn`. - current_item_id: Option, + current_item: Option, catch_scopes: Vec, loop_scopes: Vec, @@ -254,7 +254,7 @@ pub fn lower_crate( node_id_to_hir_id: IndexVec::new(), is_generator: false, is_async_body: false, - current_item_id: None, + current_item: None, is_in_trait_impl: false, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, @@ -3120,8 +3120,8 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, ref header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); - let hir_id = self.lower_node_id(id); self.with_new_scopes(|this| { + this.current_item = Some(ident.span); let mut lower_fn = |decl: &FnDecl| { // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body @@ -3159,7 +3159,6 @@ impl<'a> LoweringContext<'a> { } else { lower_fn(decl) }; - this.current_item_id = Some(hir_id); hir::ItemKind::Fn( fn_decl, @@ -3661,6 +3660,7 @@ impl<'a> LoweringContext<'a> { } else { lower_method(sig) }; + self.current_item = Some(i.span); (generics, hir::ImplItemKind::Method(sig, body_id)) } @@ -4277,6 +4277,7 @@ impl<'a> LoweringContext<'a> { let fn_decl = self.lower_fn_decl(decl, None, false, None); self.with_new_scopes(|this| { + this.current_item = Some(fn_decl_span); let mut is_generator = false; let body_id = this.lower_body(Some(decl), |this| { let e = this.lower_expr(body); @@ -5565,11 +5566,8 @@ impl<'a> LoweringContext<'a> { "`await` is only allowed inside `async` functions and blocks" ); err.span_label(await_span, "only allowed inside `async` functions and blocks"); - if let Some(item_id) = self.current_item_id { - err.span_label( - self.sess.source_map().def_span(self.items[&item_id].span), - "this function is not `async`", - ); + if let Some(item_sp) = self.current_item { + err.span_label(item_sp, "this is not `async`"); } err.emit(); return hir::ExprKind::Err; diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs index ca3654d3c8785..6b615cc9ff98f 100644 --- a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs @@ -89,5 +89,19 @@ fn foo16() -> Result<(), ()> { let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks Ok(()) } +fn foo24() -> Result<(), ()> { + fn foo() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) + } + foo() +} +fn foo25() -> Result<(), ()> { + let foo = || { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) + }; + foo() +} fn main() {} diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr index 2e2efedcf00a3..5ea59d4bcee17 100644 --- a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr @@ -91,75 +91,83 @@ LL | let _ = bar().await()?; error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:55:13 | -LL | async fn foo8() -> Result<(), ()> { - | --------------------------------- this function is not `async` -... +LL | fn foo9() -> Result<(), ()> { + | ---- this is not `async` LL | let _ = await bar(); | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:60:13 | -LL | fn foo9() -> Result<(), ()> { - | --------------------------- this function is not `async` -... +LL | fn foo10() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = await? bar(); | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:65:13 | -LL | fn foo10() -> Result<(), ()> { - | ---------------------------- this function is not `async` -... +LL | fn foo11() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = await bar()?; | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:70:14 | -LL | fn foo11() -> Result<(), ()> { - | ---------------------------- this function is not `async` -... +LL | fn foo12() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = (await bar())?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:75:13 | -LL | fn foo12() -> Result<(), ()> { - | ---------------------------- this function is not `async` -... +LL | fn foo13() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = bar().await(); | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:80:13 | -LL | fn foo13() -> Result<(), ()> { - | ---------------------------- this function is not `async` -... +LL | fn foo14() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = bar().await()?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:85:13 | -LL | fn foo14() -> Result<(), ()> { - | ---------------------------- this function is not `async` -... +LL | fn foo15() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = bar().await; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:89:13 | -LL | fn foo15() -> Result<(), ()> { - | ---------------------------- this function is not `async` -... +LL | fn foo16() -> Result<(), ()> { + | ----- this is not `async` LL | let _ = bar().await?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:94:17 + | +LL | fn foo() -> Result<(), ()> { + | --- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:101:17 + | +LL | let foo = || { + | -- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/incorrect-syntax-suggestions.rs:18:19 | @@ -169,6 +177,6 @@ LL | let _ = await bar()?; = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` = note: required by `std::ops::Try::into_result` -error: aborting due to 24 previous errors +error: aborting due to 26 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr index cb4a5e9037086..c06165b24468f 100644 --- a/src/test/ui/issues/issue-51719.stderr +++ b/src/test/ui/issues/issue-51719.stderr @@ -1,11 +1,10 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51719.rs:10:19 | -LL | async fn foo() {} - | -------------- this function is not `async` -... LL | let _gen = || foo.await; - | ^^^^^^^^^ only allowed inside `async` functions and blocks + | -- ^^^^^^^^^ only allowed inside `async` functions and blocks + | | + | this is not `async` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr index 842b99f16f256..97b63d1590ec6 100644 --- a/src/test/ui/issues/issue-51751.stderr +++ b/src/test/ui/issues/issue-51751.stderr @@ -1,9 +1,9 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51751.rs:11:20 | -LL | async fn inc(limit: i64) -> i64 { - | ------------------------------- this function is not `async` -... +LL | fn main() { + | ---- this is not `async` +LL | let result = inc(10000); LL | let finished = result.await; | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks From 0183a575f686003586ca3308db8a55d6224f4789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 May 2019 13:20:06 -0700 Subject: [PATCH 10/17] readd match await test case --- .../incorrect-syntax-suggestions.rs | 6 ++++- .../incorrect-syntax-suggestions.stderr | 27 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs index 6b615cc9ff98f..e1e5bdd3d1b92 100644 --- a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs @@ -104,4 +104,8 @@ fn foo25() -> Result<(), ()> { foo() } -fn main() {} +fn main() { + match await { await => () } + //~^ ERROR expected expression, found `=>` + //~| ERROR incorrect use of `await` +} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}` diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr index 5ea59d4bcee17..bc7bd77479e40 100644 --- a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr @@ -88,6 +88,31 @@ error: incorrect use of `await` LL | let _ = bar().await()?; | ^^ help: `await` is not a method call, remove the parentheses +error: expected expression, found `=>` + --> $DIR/incorrect-syntax-suggestions.rs:108:25 + | +LL | match await { await => () } + | ----- ^^ expected expression + | | + | while parsing this incorrect await statement + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:108:11 + | +LL | match await { await => () } + | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is not a statement: `{ await => () }.await` + +error: expected one of `.`, `?`, `{`, or an operator, found `}` + --> $DIR/incorrect-syntax-suggestions.rs:111:1 + | +LL | match await { await => () } + | ----- - expected one of `.`, `?`, `{`, or an operator here + | | + | while parsing this match expression +... +LL | } + | ^ unexpected token + error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:55:13 | @@ -177,6 +202,6 @@ LL | let _ = await bar()?; = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` = note: required by `std::ops::Try::into_result` -error: aborting due to 26 previous errors +error: aborting due to 29 previous errors For more information about this error, try `rustc --explain E0277`. From b9d6fe3ae96a7f1f478dc6baf29b8e4cff5ab865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 May 2019 13:33:26 -0700 Subject: [PATCH 11/17] 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(-) diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 32e1ee94f0dfb..61453e35095be 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 45081aadfd97b..bb0f9fa9502a0 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