From ce1d95af4c1b179536c3c0daccd62946ef20b006 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 29 Jun 2019 21:38:26 +0200 Subject: [PATCH] Always parse 'async unsafe fn' + properly ban in 2015. --- src/librustc_passes/ast_validation.rs | 7 ----- src/libsyntax/parse/parser.rs | 26 +++++++++++------ src/test/ui/async-await/async-await.rs | 13 +++++++-- .../edition-deny-async-fns-2015.rs | 6 ++++ .../edition-deny-async-fns-2015.stderr | 28 +++++++++++-------- src/test/ui/async-await/no-unsafe-async.rs | 11 ++++++++ .../ui/async-await/no-unsafe-async.stderr | 14 ++++++++++ 7 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/async-await/no-unsafe-async.rs create mode 100644 src/test/ui/async-await/no-unsafe-async.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2da9c5adf9baf..560635962995c 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -837,13 +837,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { the relevant `fold_*()` method in `PlaceholderExpander`?"); } - fn visit_fn_header(&mut self, header: &'a FnHeader) { - if header.asyncness.node.is_async() && self.session.rust_2015() { - struct_span_err!(self.session, header.asyncness.span, E0670, - "`async fn` is not permitted in the 2015 edition").emit(); - } - } - fn visit_impl_item(&mut self, ii: &'a ImplItem) { match ii.node { ImplItemKind::Method(ref sig, _) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc206580e3811..696b5f48385e7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5734,9 +5734,12 @@ impl<'a> Parser<'a> { { let is_const_fn = self.eat_keyword(kw::Const); let const_span = self.prev_span; - let unsafety = self.parse_unsafety(); let asyncness = self.parse_asyncness(); + if let IsAsync::Async { .. } = asyncness { + self.ban_async_in_2015(self.prev_span); + } let asyncness = respan(self.prev_span, asyncness); + let unsafety = self.parse_unsafety(); let (constness, unsafety, abi) = if is_const_fn { (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { @@ -7254,13 +7257,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - if self.token.span.rust_2015() { - self.diagnostic().struct_span_err_with_code( - async_span, - "`async fn` is not permitted in the 2015 edition", - DiagnosticId::Error("E0670".into()) - ).emit(); - } + self.ban_async_in_2015(async_span); return Ok(Some(item)); } } @@ -7534,6 +7531,19 @@ impl<'a> Parser<'a> { self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) } + /// We are parsing `async fn`. If we are on Rust 2015, emit an error. + fn ban_async_in_2015(&self, async_span: Span) { + if async_span.rust_2015() { + self.diagnostic() + .struct_span_err_with_code( + async_span, + "`async fn` is not permitted in the 2015 edition", + DiagnosticId::Error("E0670".into()) + ) + .emit(); + } + } + /// Parses a foreign item. crate fn parse_foreign_item(&mut self) -> PResult<'a, ForeignItem> { maybe_whole!(self, NtForeignItem, |ni| ni); diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs index 38261ca4570eb..0eae1467fbfa0 100644 --- a/src/test/ui/async-await/async-await.rs +++ b/src/test/ui/async-await/async-await.rs @@ -134,11 +134,15 @@ trait Bar { } impl Foo { - async fn async_method(x: u8) -> u8 { + async fn async_assoc_item(x: u8) -> u8 { unsafe { unsafe_async_fn(x).await } } + + async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 { + unsafe_async_fn(x).await + } } fn test_future_yields_once_then_returns(f: F) @@ -180,12 +184,17 @@ fn main() { async_fn, generic_async_fn, async_fn_with_internal_borrow, - Foo::async_method, + Foo::async_assoc_item, |x| { async move { unsafe { unsafe_async_fn(x).await } } }, + |x| { + async move { + unsafe { Foo::async_unsafe_assoc_item(x).await } + } + }, } test_with_borrow! { async_block_with_borrow_named_lifetime, diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs index e1111f9e0e4b9..a5bc181015475 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -28,6 +28,12 @@ fn main() { async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition } + accept_item! { + impl Foo { + async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition + } + } + let inside_closure = || { async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition }; diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index 05a06124dc220..efb4462095d0d 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -23,7 +23,19 @@ LL | async fn async_baz() { | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:32:9 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:38:9 | LL | async fn bar() {} | ^^^^^ @@ -35,10 +47,10 @@ LL | async fn foo() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:16:5 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 | -LL | async fn foo() {} - | ^^^^^ +LL | async fn bar() {} + | ^^^^^ error[E0706]: trait fns cannot be declared `async` --> $DIR/edition-deny-async-fns-2015.rs:20:5 @@ -46,12 +58,6 @@ error[E0706]: trait fns cannot be declared `async` LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} - | ^^^^^ - -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0670`. diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs new file mode 100644 index 0000000000000..81e0cd799ad70 --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.rs @@ -0,0 +1,11 @@ +// edition:2018 + +struct S; + +impl S { + #[cfg(FALSE)] + unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found `async` +} + +#[cfg(FALSE)] +unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found `async` diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr new file mode 100644 index 0000000000000..c339c7c3bf5bf --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -0,0 +1,14 @@ +error: expected one of `extern` or `fn`, found `async` + --> $DIR/no-unsafe-async.rs:7:12 + | +LL | unsafe async fn g() {} + | ^^^^^ expected one of `extern` or `fn` here + +error: expected one of `extern`, `fn`, or `{`, found `async` + --> $DIR/no-unsafe-async.rs:11:8 + | +LL | unsafe async fn f() {} + | ^^^^^ expected one of `extern`, `fn`, or `{` here + +error: aborting due to 2 previous errors +