diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6168647183fdb..23aaafac934ee 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -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 @@ -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 @@ -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(); diff --git a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs index ea67831b68e67..a13a255d53610 100644 --- a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs +++ b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs @@ -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() {} diff --git a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr index 6c3044e64d20c..0292c53fb1c17 100644 --- a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr +++ b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr @@ -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 } @@ -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 } @@ -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 } | ^^^^^ @@ -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 } | ^^^^^ diff --git a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs index ee04f74c8a64b..9b03ec7553d18 100644 --- a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs +++ b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs @@ -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() {} diff --git a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr deleted file mode 100644 index a4e77154b17d1..0000000000000 --- a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: expected identifier, found `]` - --> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:16 - | -LL | ($Type:ty) => { - | -------- while parsing argument for this `ty` macro fragment -... -LL | check! { [const] Trait } - | ^ expected identifier - -error[E0658]: const trait impls are experimental - --> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:11 - | -LL | check! { [const] Trait } - | ^^^^^ - | - = note: see issue #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 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs index 35e964eacec4f..3f70ffa7d10e7 100644 --- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs @@ -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() {} diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr index 7a4061d9c18e5..383936b9df155 100644 --- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr @@ -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 } | ^^^^^ @@ -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 - = 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 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 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 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`. diff --git a/tests/ui/traits/const-traits/macro-dyn-const-2015.rs b/tests/ui/traits/const-traits/macro-dyn-const-2015.rs index fadfbe667887d..0dfa482b98613 100644 --- a/tests/ui/traits/const-traits/macro-dyn-const-2015.rs +++ b/tests/ui/traits/const-traits/macro-dyn-const-2015.rs @@ -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() {} diff --git a/tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs new file mode 100644 index 0000000000000..75077577b8c6e --- /dev/null +++ b/tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs @@ -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: +check!(impl [T] Trait); +check!(impl [T: Bound] Trait); + +fn main() {}