Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
}

fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
// `Not`, `Tilde` & `Const` are deliberately not part of this list to
// `!`, `const`, `[`, `async` are deliberately not part of this list to
// contain the number of potential regressions esp. in MBE code.
// `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`.
// `Not` would regress `dyn!(...)` macro calls in Rust 2015.
// `const` and `[` would regress UI test `macro-dyn-const-2015.rs`.
// `!` would regress `dyn!(...)` macro calls in Rust 2015.
t.is_path_start()
|| t.is_lifetime()
|| t == &TokenKind::Question
Expand Down Expand Up @@ -1015,12 +1015,18 @@ impl<'a> Parser<'a> {
|| self.check(exp!(Tilde))
|| self.check_keyword(exp!(For))
|| self.check(exp!(OpenParen))
|| self.check(exp!(OpenBracket))
|| self.can_begin_maybe_const_bound()
|| self.check_keyword(exp!(Const))
|| self.check_keyword(exp!(Async))
|| self.check_keyword(exp!(Use))
}

fn can_begin_maybe_const_bound(&mut self) -> bool {
self.check(exp!(OpenBracket))
&& self.look_ahead(1, |t| t.is_keyword(kw::Const))
&& self.look_ahead(2, |t| *t == token::CloseBracket)
}

/// Parse a bound.
///
/// ```ebnf
Expand Down Expand Up @@ -1199,10 +1205,7 @@ impl<'a> Parser<'a> {
let span = tilde.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::const_trait_impl, span);
BoundConstness::Maybe(span)
} else if self.check(exp!(OpenBracket))
&& self.look_ahead(1, |t| t.is_keyword(kw::Const))
&& self.look_ahead(2, |t| *t == token::CloseBracket)
{
} else if self.can_begin_maybe_const_bound() {
let start = self.token.span;
self.bump();
self.expect_keyword(exp!(Const)).unwrap();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
// Demonstrates and records a theoretical regressions / breaking changes caused by the
// introduction of async trait bounds.

// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018.
// Setting the edition to >2015 since we didn't regress `demo! { dyn async }` in Rust 2015.
//@ edition:2018

macro_rules! demo {
($ty:ty) => { compile_error!("ty"); };
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
//~^ ERROR ty
//~| ERROR ty
(impl $c:ident Trait) => {};
(dyn $c:ident Trait) => {};

// DON'T MODIFY THE MATCHERS BELOW UNLESS THE ASYNC TRAIT MODIFIER SYNTAX CHANGES!

(impl $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
(dyn $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
}

demo! { impl async Trait }
//~^ ERROR `async` trait bounds are unstable
demo! { impl async Trait } //~ ERROR `async` trait bounds are unstable

demo! { dyn async Trait }
//~^ ERROR `async` trait bounds are unstable
demo! { dyn async Trait } //~ ERROR `async` trait bounds are unstable

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error: ty
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19
|
LL | ($ty:ty) => { compile_error!("ty"); };
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { impl async Trait }
Expand All @@ -12,7 +12,7 @@ LL | demo! { impl async Trait }
error: ty
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19
|
LL | ($ty:ty) => { compile_error!("ty"); };
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { dyn async Trait }
Expand All @@ -21,7 +21,7 @@ LL | demo! { dyn async Trait }
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0658]: `async` trait bounds are unstable
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:15:14
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:14
|
LL | demo! { impl async Trait }
| ^^^^^
Expand All @@ -32,7 +32,7 @@ LL | demo! { impl async Trait }
= help: use the desugared name of the async trait, such as `AsyncFn`

error[E0658]: `async` trait bounds are unstable
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:13
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:20:13
|
LL | demo! { dyn async Trait }
| ^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
// Ensure that we don't consider `const Trait` to
// match the macro fragment specifier `ty` as that would be a breaking
// change theoretically speaking. Syntactically trait object types can
// be "bare", i.e., lack the prefix `dyn`.
// By contrast, `?Trait` *does* match `ty` and therefore an arm like
// `?$Trait:path` would never be reached.
// See `parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs`.
// `[const] Trait` is already an error for a `ty` fragment,
// so we do not need to prevent that.
// Ensure that we don't consider `const Trait` to match the macro fragment specifier `ty`
// as that would be a breaking change theoretically speaking.
//
// Syntactically trait object types can be "bare", i.e., lack the prefix `dyn`.
// By contrast, `?Trait` *does* match `ty` and therefore an arm like `?$Trait:path`
// would never be reached. See `parser/macro/macro-bare-trait-object-maybe-trait-bound.rs`.

//@ check-pass (KEEP THIS AS A PASSING TEST!)

macro_rules! check {
($Type:ty) => {
compile_error!("ty");
};
(const $Trait:path) => {};
([const] $Trait:path) => { [const] Trait };
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!

// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!

(const $Trait:path) => { /* KEEP THIS EMPTY! */ };
// We don't need to check `[const] Trait` here since that matches the `ty` fragment
// already anyway since `[` may begin a slice or array type. However, it'll then
// subsequently fail due to #146122 (section 3).
}

check! { const Trait }
check! { [const] Trait }
//~^ ERROR: expected identifier, found `]`
//~| ERROR: const trait impls are experimental

fn main() {}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
// Demonstrates and records a theoretical regressions / breaking changes caused by the
// introduction of const trait bounds.
// introduction of `const` and `[const]` trait bounds.

// Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018.
// Setting the edition to >2015 since we didn't regress `demo! { dyn const }` in Rust 2015.
// See also test `traits/const-traits/macro-dyn-const-2015.rs`.
//@ edition:2018

trait Trait {}

macro_rules! demo {
(impl $c:ident Trait) => { impl $c Trait {} };
//~^ ERROR inherent
//~| WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
(dyn $c:ident Trait) => { dyn $c Trait {} }; //~ ERROR macro expansion
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
//~^ ERROR ty
//~| ERROR ty
//~| ERROR ty
//~| ERROR ty

// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!

(impl $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
(dyn $c:ident Trait) => { /* KEEP THIS EMPTY! */ };

(impl [const] Trait) => { /* KEEP THIS EMPTY! */ };
(dyn [const] Trait) => { /* KEEP THIS EMPTY! */ };
}

demo! { impl const Trait }
//~^ ERROR const trait impls are experimental
demo! { impl const Trait } //~ ERROR const trait impls are experimental
demo! { dyn const Trait } //~ ERROR const trait impls are experimental

demo! { dyn const Trait }
demo! { impl [const] Trait } //~ ERROR const trait impls are experimental
demo! { dyn [const] Trait } //~ ERROR const trait impls are experimental

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
error: inherent impls cannot be const
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
error: ty
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
LL | (impl $c:ident Trait) => { impl $c Trait {} };
| ^^^^^ inherent impl for this type
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { impl const Trait }
| --------------------------
| | |
| | const because of this
| in this macro invocation
| -------------------------- in this macro invocation
|
= note: only trait implementations may be annotated with `const`
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)

error: macro expansion ignores keyword `dyn` and any tokens following
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31
error: ty
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
LL | (dyn $c:ident Trait) => { dyn $c Trait {} };
| ^^^
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { dyn const Trait }
| ------------------------- caused by the macro expansion here
| ------------------------- in this macro invocation
|
= note: the usage of `demo!` is likely invalid in item context
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)

error: ty
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { impl [const] Trait }
| ---------------------------- in this macro invocation
|
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)

error: ty
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { dyn [const] Trait }
| --------------------------- in this macro invocation
|
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0658]: const trait impls are experimental
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:17:14
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:26:14
|
LL | demo! { impl const Trait }
| ^^^^^
Expand All @@ -34,24 +52,36 @@ LL | demo! { impl const Trait }
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
error[E0658]: const trait impls are experimental
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:27:13
|
LL | (impl $c:ident Trait) => { impl $c Trait {} };
| ^^^^^
...
LL | demo! { impl const Trait }
| -------------------------- in this macro invocation
LL | demo! { dyn const Trait }
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
= note: this warning originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
help: you might have intended to implement this trait for a given type
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: const trait impls are experimental
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:29:14
|
LL | demo! { impl [const] Trait }
| ^^^^^^^
|
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: const trait impls are experimental
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:30:13
|
LL | (impl $c:ident Trait) => { impl $c Trait for /* Type */ {} };
| ++++++++++++++
LL | demo! { dyn [const] Trait }
| ^^^^^^^
|
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 3 previous errors; 1 warning emitted
error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0658`.
15 changes: 10 additions & 5 deletions tests/ui/traits/const-traits/macro-dyn-const-2015.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
// Ensure that the introduction of const trait bound didn't regress this code in Rust 2015.
// See also `mbe-const-trait-bound-theoretical-regression.rs`.
// Ensure that the introduction of `const` and `[const]` trait bounds didn't regress this
// Rust 2015 code. See also test `macro-const-trait-bound-theoretical-regression.rs`.

//@ edition: 2015
//@ check-pass
//@ check-pass (KEEP THIS AS A PASSING TEST!)

macro_rules! check {
($ty:ty) => { compile_error!("ty"); };
(dyn $c:ident) => {};
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!

// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!

(dyn $c:ident) => { /* KEEP THIS EMPTY! */ };
(dyn [$c:ident]) => { /* KEEP THIS EMPTY! */ };
}

check! { dyn const }
check! { dyn [const] }

fn main() {}
25 changes: 25 additions & 0 deletions tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Ensure that we don't consider `[` to begin trait bounds to contain breakages.
// Only `[const]` in its entirety begins a trait bound.
// See also test `macro-const-trait-bound-theoretical-regression.rs`.

//@ check-pass (KEEP THIS AS A PASSING TEST!)
// Setting the edition to >2015 since we didn't regress `check! { dyn [const] Trait }` in Rust 2015.
// See also test `traits/const-traits/macro-dyn-const-2015.rs`.
//@ edition:2018

macro_rules! check {
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!

// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!

(dyn [$($any:tt)*] Trait) => { /* KEEP THIS EMPTY! */ };
(impl [$($any:tt)*] Trait) => { /* KEEP THIS EMPTY! */ };
}

check!(dyn [T] Trait);

// issue: <https://github.com/rust-lang/rust/issues/146417>
check!(impl [T] Trait);
check!(impl [T: Bound] Trait);

fn main() {}
Loading