about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-06-30 21:57:30 +0200
committerGitHub <noreply@github.com>2019-06-30 21:57:30 +0200
commit43eba5fef287cfcd63b36321900d546be9496476 (patch)
treef7261e5e2bd80050f575d4bc9be69da46a69db85 /src
parent690f9e422ec6e7fdce8dfb7ee1b35cdddede409d (diff)
parentce1d95af4c1b179536c3c0daccd62946ef20b006 (diff)
downloadrust-43eba5fef287cfcd63b36321900d546be9496476.tar.gz
rust-43eba5fef287cfcd63b36321900d546be9496476.zip
Rollup merge of #62241 - Centril:fix-async-unsafe-order, r=petrochenkov
Always parse 'async unsafe fn' + properly ban in 2015

Parse `async unsafe fn` not `unsafe async fn` in implementations. We also take the opportunity to properly ban `async fn` in Rust 2015 when they are inside implementations.

Closes https://github.com/rust-lang/rust/issues/62232.

cc https://github.com/rust-lang/rust/pull/61319, https://github.com/rust-lang/rust/issues/62121, and https://github.com/rust-lang/rust/issues/62149.

r? @petrochenkov
Diffstat (limited to 'src')
-rw-r--r--src/librustc_passes/ast_validation.rs7
-rw-r--r--src/libsyntax/parse/parser.rs26
-rw-r--r--src/test/ui/async-await/async-await.rs13
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.rs6
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.stderr28
-rw-r--r--src/test/ui/async-await/no-unsafe-async.rs11
-rw-r--r--src/test/ui/async-await/no-unsafe-async.stderr14
7 files changed, 77 insertions, 28 deletions
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 2da9c5adf9b..56063596299 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 fc206580e38..696b5f48385 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 38261ca4570..0eae1467fbf 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, Fut>(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 e1111f9e0e4..a5bc1810154 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 05a06124dc2..efb4462095d 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 00000000000..81e0cd799ad
--- /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 00000000000..c339c7c3bf5
--- /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
+