about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-01-26 17:15:43 +0000
committerMichael Goulet <michael@errs.io>2024-01-31 16:59:19 +0000
commit54db272cc972f232cc50a7c6dff30140f904738a (patch)
tree9775fa1132e2714224af35dacb6b104dda3a39bc
parentcd2fd34ca68f701ade233a980093ee4444f7da3a (diff)
downloadrust-54db272cc972f232cc50a7c6dff30140f904738a.tar.gz
rust-54db272cc972f232cc50a7c6dff30140f904738a.zip
Better error message in ed 2015
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs9
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs15
-rw-r--r--tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs10
-rw-r--r--tests/ui/async-await/async-fn/edition-2015.rs11
-rw-r--r--tests/ui/async-await/async-fn/edition-2015.stderr51
6 files changed, 75 insertions, 23 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index aac8c0b3103..7c2ecf34c17 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -22,6 +22,8 @@ parse_associated_static_item_not_allowed = associated `static` items are not all
 
 parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
 
+parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Rust 2018 or later
+
 parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
     .label = to use `async fn`, switch to Rust 2018 or later
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 4e4bf9bdad9..86a64d90deb 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1589,6 +1589,15 @@ pub(crate) struct AsyncMoveBlockIn2015 {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_async_bound_modifier_in_2015)]
+pub(crate) struct AsyncBoundModifierIn2015 {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub help: HelpUseLatestEdition,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_self_argument_pointer)]
 pub(crate) struct SelfArgumentPointer {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 72089dc2a91..5fe54a536a7 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -3,8 +3,8 @@ use super::{Parser, PathStyle, TokenType};
 use crate::errors::{
     self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
     FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
-    InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
-    ReturnTypesUseThinArrow,
+    HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
+    NestedCVariadicType, ReturnTypesUseThinArrow,
 };
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
@@ -882,6 +882,17 @@ impl<'a> Parser<'a> {
         let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) {
             self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
             BoundAsyncness::Async(self.prev_token.span)
+        } else if self.may_recover()
+            && self.token.span.is_rust_2015()
+            && self.is_kw_followed_by_ident(kw::Async)
+        {
+            self.bump(); // eat `async`
+            self.dcx().emit_err(errors::AsyncBoundModifierIn2015 {
+                span: self.prev_token.span,
+                help: HelpUseLatestEdition::new(),
+            });
+            self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
+            BoundAsyncness::Async(self.prev_token.span)
         } else {
             BoundAsyncness::Normal
         };
diff --git a/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs
new file mode 100644
index 00000000000..6436787b665
--- /dev/null
+++ b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs
@@ -0,0 +1,10 @@
+// check-pass
+// Make sure that we don't eagerly recover `async ::Bound` in edition 2015.
+
+mod async {
+    pub trait Foo {}
+}
+
+fn test(x: impl async ::Foo) {}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-fn/edition-2015.rs b/tests/ui/async-await/async-fn/edition-2015.rs
index 287d05ecacb..83b9d415dda 100644
--- a/tests/ui/async-await/async-fn/edition-2015.rs
+++ b/tests/ui/async-await/async-fn/edition-2015.rs
@@ -1,8 +1,7 @@
-// FIXME(async_closures): This error message could be made better.
-
-fn foo(x: impl async Fn()) -> impl async Fn() {}
-//~^ ERROR expected
-//~| ERROR expected
-//~| ERROR expected
+fn foo(x: impl async Fn()) -> impl async Fn() { x }
+//~^ ERROR `async` trait bounds are only allowed in Rust 2018 or later
+//~| ERROR `async` trait bounds are only allowed in Rust 2018 or later
+//~| ERROR async closures are unstable
+//~| ERROR async closures are unstable
 
 fn main() {}
diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr
index e79b92ccf9f..0029d53868d 100644
--- a/tests/ui/async-await/async-fn/edition-2015.stderr
+++ b/tests/ui/async-await/async-fn/edition-2015.stderr
@@ -1,22 +1,43 @@
-error: expected one of `:` or `|`, found `)`
-  --> $DIR/edition-2015.rs:3:26
+error: `async` trait bounds are only allowed in Rust 2018 or later
+  --> $DIR/edition-2015.rs:1:16
    |
-LL | fn foo(x: impl async Fn()) -> impl async Fn() {}
-   |                          ^ expected one of `:` or `|`
+LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
+   |                ^^^^^
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: `async` trait bounds are only allowed in Rust 2018 or later
+  --> $DIR/edition-2015.rs:1:36
+   |
+LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
+   |                                    ^^^^^
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `Fn`
-  --> $DIR/edition-2015.rs:3:22
+error[E0658]: async closures are unstable
+  --> $DIR/edition-2015.rs:1:16
+   |
+LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
+   |                ^^^^^
    |
-LL | fn foo(x: impl async Fn()) -> impl async Fn() {}
-   |                     -^^ expected one of `(`, `)`, `+`, `,`, `::`, or `<`
-   |                     |
-   |                     help: missing `,`
+   = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
+   = help: add `#![feature(async_closure)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: to use an async block, remove the `||`: `async {`
 
-error: expected one of `(`, `+`, `::`, `<`, `where`, or `{`, found `Fn`
-  --> $DIR/edition-2015.rs:3:42
+error[E0658]: async closures are unstable
+  --> $DIR/edition-2015.rs:1:36
+   |
+LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
+   |                                    ^^^^^
    |
-LL | fn foo(x: impl async Fn()) -> impl async Fn() {}
-   |                                          ^^ expected one of `(`, `+`, `::`, `<`, `where`, or `{`
+   = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
+   = help: add `#![feature(async_closure)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: to use an async block, remove the `||`: `async {`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0658`.