Skip to content

Commit

Permalink
Rollup merge of rust-lang#62241 - Centril:fix-async-unsafe-order, r=p…
Browse files Browse the repository at this point in the history
…etrochenkov

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 rust-lang#62232.

cc rust-lang#61319, rust-lang#62121, and rust-lang#62149.

r? @petrochenkov
  • Loading branch information
Centril committed Jun 30, 2019
2 parents 690f9e4 + ce1d95a commit 43eba5f
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 28 deletions.
7 changes: 0 additions & 7 deletions src/librustc_passes/ast_validation.rs
Expand Up @@ -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, _) => {
Expand Down
26 changes: 18 additions & 8 deletions src/libsyntax/parse/parser.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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));
}
}
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 11 additions & 2 deletions src/test/ui/async-await/async-await.rs
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/async-await/edition-deny-async-fns-2015.rs
Expand Up @@ -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
};
Expand Down
28 changes: 17 additions & 11 deletions src/test/ui/async-await/edition-deny-async-fns-2015.stderr
Expand Up @@ -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() {}
| ^^^^^
Expand All @@ -35,23 +47,17 @@ 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
|
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`.
11 changes: 11 additions & 0 deletions 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`
14 changes: 14 additions & 0 deletions 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

0 comments on commit 43eba5f

Please sign in to comment.