Skip to content

Commit 77ab04d

Browse files
Support async trait bounds in macros
1 parent bc1b9e0 commit 77ab04d

14 files changed

+197
-27
lines changed

compiler/rustc_parse/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Ru
2727
parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
2828
.label = to use `async fn`, switch to Rust 2018 or later
2929
30+
parse_async_impl = `async` trait implementations are unsupported
31+
3032
parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later
3133
3234
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect

compiler/rustc_parse/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2971,3 +2971,10 @@ pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span);
29712971
#[derive(Diagnostic)]
29722972
#[diag(parse_invalid_offset_of)]
29732973
pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span);
2974+
2975+
#[derive(Diagnostic)]
2976+
#[diag(parse_async_impl)]
2977+
pub(crate) struct AsyncImpl {
2978+
#[primary_span]
2979+
pub span: Span,
2980+
}

compiler/rustc_parse/src/parser/item.rs

+8
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,14 @@ impl<'a> Parser<'a> {
562562
self.sess.gated_spans.gate(sym::const_trait_impl, span);
563563
}
564564

565+
// Parse stray `impl async Trait`
566+
if (self.token.span.at_least_rust_2018() && self.token.is_keyword(kw::Async))
567+
|| (self.token.span.is_rust_2015() && self.is_kw_followed_by_ident(kw::Async))
568+
{
569+
self.bump();
570+
self.dcx().emit_err(errors::AsyncImpl { span: self.prev_token.span });
571+
}
572+
565573
let polarity = self.parse_polarity();
566574

567575
// Parse both types and traits as a type, then reinterpret if necessary.

compiler/rustc_parse/src/parser/ty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -776,9 +776,10 @@ impl<'a> Parser<'a> {
776776
|| self.check(&token::Not)
777777
|| self.check(&token::Question)
778778
|| self.check(&token::Tilde)
779-
|| self.check_keyword(kw::Const)
780779
|| self.check_keyword(kw::For)
781780
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
781+
|| self.is_kw_followed_by_ident(kw::Const)
782+
|| self.is_kw_followed_by_ident(kw::Async)
782783
}
783784

784785
/// Parses a bound according to the grammar:

tests/ui/async-await/async-fn/impl-header.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
struct F;
44

55
impl async Fn<()> for F {}
6-
//~^ ERROR expected type, found keyword `async`
6+
//~^ ERROR `async` trait implementations are unsupported
7+
//~| ERROR the precise format of `Fn`-family traits' type parameters is subject to change
8+
//~| ERROR manual implementations of `Fn` are experimental
9+
//~| ERROR expected a `FnMut()` closure, found `F`
10+
//~| ERROR not all trait items implemented, missing: `call`
711

812
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,47 @@
1-
error: expected type, found keyword `async`
1+
error: `async` trait implementations are unsupported
22
--> $DIR/impl-header.rs:5:6
33
|
44
LL | impl async Fn<()> for F {}
5-
| ^^^^^ expected type
5+
| ^^^^^
66

7-
error: aborting due to 1 previous error
7+
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
8+
--> $DIR/impl-header.rs:5:12
9+
|
10+
LL | impl async Fn<()> for F {}
11+
| ^^^^^^
12+
|
13+
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
14+
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
15+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
16+
17+
error[E0183]: manual implementations of `Fn` are experimental
18+
--> $DIR/impl-header.rs:5:12
19+
|
20+
LL | impl async Fn<()> for F {}
21+
| ^^^^^^ manual implementations of `Fn` are experimental
22+
|
23+
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
24+
25+
error[E0277]: expected a `FnMut()` closure, found `F`
26+
--> $DIR/impl-header.rs:5:23
27+
|
28+
LL | impl async Fn<()> for F {}
29+
| ^ expected an `FnMut()` closure, found `F`
30+
|
31+
= help: the trait `FnMut<()>` is not implemented for `F`
32+
= note: wrap the `F` in a closure with no arguments: `|| { /* code */ }`
33+
note: required by a bound in `Fn`
34+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
35+
36+
error[E0046]: not all trait items implemented, missing: `call`
37+
--> $DIR/impl-header.rs:5:1
38+
|
39+
LL | impl async Fn<()> for F {}
40+
| ^^^^^^^^^^^^^^^^^^^^^^^ missing `call` in implementation
41+
|
42+
= help: implement the missing item: `fn call(&self, _: ()) -> <Self as FnOnce<()>>::Output { todo!() }`
43+
44+
error: aborting due to 5 previous errors
845

46+
Some errors have detailed explanations: E0046, E0183, E0277, E0658.
47+
For more information about an error, try `rustc --explain E0046`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Demonstrates and records a theoretical regressions / breaking changes caused by the
2+
// introduction of async trait bounds.
3+
4+
// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018.
5+
// edition:2018
6+
7+
macro_rules! demo {
8+
($ty:ty) => { compile_error!("ty"); };
9+
//~^ ERROR ty
10+
//~| ERROR ty
11+
(impl $c:ident Trait) => {};
12+
(dyn $c:ident Trait) => {};
13+
}
14+
15+
demo! { impl async Trait }
16+
//~^ ERROR async closures are unstable
17+
18+
demo! { dyn async Trait }
19+
//~^ ERROR async closures are unstable
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: ty
2+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19
3+
|
4+
LL | ($ty:ty) => { compile_error!("ty"); };
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
...
7+
LL | demo! { impl async Trait }
8+
| -------------------------- in this macro invocation
9+
|
10+
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
12+
error: ty
13+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19
14+
|
15+
LL | ($ty:ty) => { compile_error!("ty"); };
16+
| ^^^^^^^^^^^^^^^^^^^^
17+
...
18+
LL | demo! { dyn async Trait }
19+
| ------------------------- in this macro invocation
20+
|
21+
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
22+
23+
error[E0658]: async closures are unstable
24+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:15:14
25+
|
26+
LL | demo! { impl async Trait }
27+
| ^^^^^
28+
|
29+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
30+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
31+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
32+
= help: to use an async block, remove the `||`: `async {`
33+
34+
error[E0658]: async closures are unstable
35+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:18:13
36+
|
37+
LL | demo! { dyn async Trait }
38+
| ^^^^^
39+
|
40+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
41+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
42+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
43+
= help: to use an async block, remove the `||`: `async {`
44+
45+
error: aborting due to 4 previous errors
46+
47+
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// edition: 2021
2+
3+
macro_rules! x {
4+
($x:item) => {}
5+
}
6+
7+
x! {
8+
async fn foo() -> impl async Fn() { }
9+
//~^ ERROR async closures are unstable
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0658]: async closures are unstable
2+
--> $DIR/trait-bounds-in-macro.rs:8:28
3+
|
4+
LL | async fn foo() -> impl async Fn() { }
5+
| ^^^^^
6+
|
7+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
8+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
= help: to use an async block, remove the `||`: `async {`
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0658`.

tests/ui/parser/trait-object-delimiters.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
88
fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
99

1010
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
11-
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{`
11+
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
1212
//~| ERROR at least one trait is required for an object type
1313

1414
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`

tests/ui/parser/trait-object-delimiters.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ error: expected parameter name, found `{`
3434
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
3535
| ^ expected parameter name
3636

37-
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{`
37+
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
3838
--> $DIR/trait-object-delimiters.rs:10:17
3939
|
4040
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
41-
| -^ expected one of 11 possible tokens
41+
| -^ expected one of 10 possible tokens
4242
| |
4343
| help: missing `,`
4444

tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66

77
macro_rules! demo {
88
($ty:ty) => { compile_error!("ty"); };
9-
(impl $c:ident) => {};
10-
(dyn $c:ident) => {};
9+
//~^ ERROR ty
10+
//~| ERROR ty
11+
(impl $c:ident Trait) => {};
12+
(dyn $c:ident Trait) => {};
1113
}
1214

13-
demo! { impl const }
14-
//~^ ERROR expected identifier, found `<eof>`
15+
demo! { impl const Trait }
16+
//~^ ERROR const trait impls are experimental
1517

16-
demo! { dyn const }
18+
demo! { dyn const Trait }
1719
//~^ ERROR const trait impls are experimental
18-
//~| ERROR expected identifier, found `<eof>`
1920

2021
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,45 @@
1-
error: expected identifier, found `<eof>`
2-
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:13:14
1+
error: ty
2+
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19
33
|
44
LL | ($ty:ty) => { compile_error!("ty"); };
5-
| ------ while parsing argument for this `ty` macro fragment
5+
| ^^^^^^^^^^^^^^^^^^^^
66
...
7-
LL | demo! { impl const }
8-
| ^^^^^ expected identifier
7+
LL | demo! { impl const Trait }
8+
| -------------------------- in this macro invocation
9+
|
10+
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
911

10-
error: expected identifier, found `<eof>`
11-
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13
12+
error: ty
13+
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19
1214
|
1315
LL | ($ty:ty) => { compile_error!("ty"); };
14-
| ------ while parsing argument for this `ty` macro fragment
16+
| ^^^^^^^^^^^^^^^^^^^^
1517
...
16-
LL | demo! { dyn const }
17-
| ^^^^^ expected identifier
18+
LL | demo! { dyn const Trait }
19+
| ------------------------- in this macro invocation
20+
|
21+
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
22+
23+
error[E0658]: const trait impls are experimental
24+
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:15:14
25+
|
26+
LL | demo! { impl const Trait }
27+
| ^^^^^
28+
|
29+
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
30+
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
31+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1832

1933
error[E0658]: const trait impls are experimental
20-
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13
34+
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:18:13
2135
|
22-
LL | demo! { dyn const }
36+
LL | demo! { dyn const Trait }
2337
| ^^^^^
2438
|
2539
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
2640
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
2741
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2842

29-
error: aborting due to 3 previous errors
43+
error: aborting due to 4 previous errors
3044

3145
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)