Emit pre-expansion feature gate warning for item modifier default

This commit is contained in:
León Orell Valerian Liehr
2026-03-28 19:20:21 +01:00
parent 394012bcd2
commit 92fbfae16b
13 changed files with 238 additions and 32 deletions
+13 -2
View File
@@ -224,7 +224,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
}
if let ast::Defaultness::Default(_) = of_trait.defaultness {
gate!(self, specialization, i.span, "specialization is unstable");
gate!(self, specialization, i.span, "specialization is experimental");
}
}
@@ -450,7 +450,7 @@ fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
self.features.specialization() || (is_fn && self.features.min_specialization()),
sym::specialization,
i.span,
"specialization is unstable"
"specialization is experimental"
);
}
visit::walk_assoc_item(self, i, ctxt)
@@ -615,10 +615,21 @@ macro_rules! soft_gate_all_legacy_dont_use {
soft_gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
soft_gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
soft_gate_all_legacy_dont_use!(negative_impls, "negative impls are experimental");
soft_gate_all_legacy_dont_use!(specialization, "specialization is experimental");
soft_gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
soft_gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
// tidy-alphabetical-end
for &span in spans.get(&sym::min_specialization).into_iter().flatten() {
if !visitor.features.specialization()
&& !visitor.features.min_specialization()
&& !span.allows_unstable(sym::specialization)
&& !span.allows_unstable(sym::min_specialization)
{
feature_warn(visitor.sess, sym::specialization, span, "specialization is experimental");
}
}
// -----------------------------------------------------------------------------
visit::walk_crate(&mut visitor, krate);
+10 -1
View File
@@ -248,10 +248,18 @@ fn parse_item_kind(
self.parse_use_item()?
} else if self.check_fn_front_matter(check_pub, case) {
// FUNCTION ITEM
let defaultness = def_();
if let Defaultness::Default(span) = defaultness {
// Default functions should only require feature `min_specialization`. We remove the
// `specialization` tag again as such spans *require* feature `specialization` to be
// enabled. In a later stage, we make `specialization` imply `min_specialization`.
self.psess.gated_spans.gate(sym::min_specialization, span);
self.psess.gated_spans.ungate_last(sym::specialization, span);
}
let (ident, sig, generics, contract, body) =
self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
ItemKind::Fn(Box::new(Fn {
defaultness: def_(),
defaultness,
ident,
sig,
generics,
@@ -1016,6 +1024,7 @@ fn parse_defaultness(&mut self) -> Defaultness {
if self.check_keyword(exp!(Default))
&& self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As))
{
self.psess.gated_spans.gate(sym::specialization, self.token.span);
self.bump(); // `default`
Defaultness::Default(self.prev_token_uninterpolated_span())
} else if self.eat_keyword(exp!(Final)) {
+2 -1
View File
@@ -9,12 +9,13 @@
#![feature(const_trait_impl)]
#![feature(coroutines)]
#![feature(decl_macro)]
#![feature(macro_guard_matcher)]
#![feature(more_qualified_paths)]
#![feature(never_patterns)]
#![feature(specialization)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![feature(macro_guard_matcher)]
#![deny(unused_macros)]
// These macros force the use of AST pretty-printing by converting the input to
@@ -1,4 +1,5 @@
//@ check-pass
#![feature(specialization)]
fn main() {}
@@ -0,0 +1,21 @@
trait Trait {
type Ty;
const CT: ();
fn fn_(&self);
}
impl<T> Trait for T {
default type Ty = (); //~ ERROR specialization is experimental
default const CT: () = (); //~ ERROR specialization is experimental
default fn fn_(&self) {} //~ ERROR specialization is experimental
}
trait OtherTrait {
fn fn_();
}
default impl<T> OtherTrait for T { //~ ERROR specialization is experimental
fn fn_() {}
}
fn main() {}
@@ -0,0 +1,45 @@
error[E0658]: specialization is experimental
--> $DIR/feature-gate-specialization.rs:8:5
|
LL | default type Ty = ();
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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]: specialization is experimental
--> $DIR/feature-gate-specialization.rs:9:5
|
LL | default const CT: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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]: specialization is experimental
--> $DIR/feature-gate-specialization.rs:10:5
|
LL | default fn fn_(&self) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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]: specialization is experimental
--> $DIR/feature-gate-specialization.rs:17:1
|
LL | / default impl<T> OtherTrait for T {
LL | | fn fn_() {}
LL | | }
| |_^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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 4 previous errors
For more information about this error, try `rustc --explain E0658`.
@@ -0,0 +1,62 @@
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:21:5
|
LL | default type Ty = ();
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:24:5
|
LL | default const CT: () = ();
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:40:1
|
LL | default impl Trait for () {}
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:27:5
|
LL | default fn fn_();
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:35:1
|
LL | default fn fn_() {}
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: 5 warnings emitted
@@ -0,0 +1,38 @@
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:21:5
|
LL | default type Ty = ();
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:24:5
|
LL | default const CT: () = ();
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: specialization is experimental
--> $DIR/soft-feature-gate-specialization.rs:40:1
|
LL | default impl Trait for () {}
| ^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: 3 warnings emitted
@@ -0,0 +1,44 @@
// For historical reasons, item modifier `default` doesn't have a proper pre-expansion feature gate.
// We're now at least issuing a *warning* for those that only exist before macro expansion.
// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one.
// As part of this, move these test cases into `feature-gate-specialization.rs`.
//
// Moreover, `specialization` implies `min_specialization` similar to the post-expansion gate.
//
// However, while we only gate `default` *associated* functions only behind `min_specialization` OR
// `specialization` in the post-expansion case, in the pre-expansion case we gate all kinds of
// functions (free, assoc, foreign) behind `min_specialization` OR `specialization` if marked with
// `default` for simplicity of implementation. Ultimately it doesn't matter since we later reject
// `default` on anything other than impls & impl assoc items during semantic analysis.
//
//@ revisions: default min full
//@ check-pass
#![cfg_attr(min, feature(min_specialization))]
#![cfg_attr(full, feature(specialization))]
#[cfg(false)]
impl Trait for () {
default type Ty = ();
//[default,min]~^ WARN specialization is experimental
//[default,min]~| WARN unstable syntax can change at any point in the future
default const CT: () = ();
//[default,min]~^ WARN specialization is experimental
//[default,min]~| WARN unstable syntax can change at any point in the future
default fn fn_();
//[default]~^ WARN specialization is experimental
//[default]~| WARN unstable syntax can change at any point in the future
}
// While free ty/ct/fn items marked `default` are
// semantically malformed we still need to gate the keyword!
#[cfg(false)]
default fn fn_() {}
//[default]~^ WARN specialization is experimental
//[default]~| WARN unstable syntax can change at any point in the future
#[cfg(false)]
default impl Trait for () {}
//[default,min]~^ WARN specialization is experimental
//[default,min]~| WARN unstable syntax can change at any point in the future
fn main() {}
@@ -1,13 +0,0 @@
// Check that specialization must be ungated to use the `default` keyword
// gate-test-specialization
trait Foo {
fn foo(&self);
}
impl<T> Foo for T {
default fn foo(&self) {} //~ ERROR specialization is unstable
}
fn main() {}
@@ -1,13 +0,0 @@
error[E0658]: specialization is unstable
--> $DIR/specialization-feature-gate-default.rs:10:5
|
LL | default fn foo(&self) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: add `#![feature(specialization)]` 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 1 previous error
For more information about this error, try `rustc --explain E0658`.
+1 -1
View File
@@ -12,7 +12,7 @@ pub trait Foo {
impl<T> Foo for T {
default fn bar() {}
//~^ ERROR specialization is unstable
//~^ ERROR specialization is experimental
//~| NOTE created at
}
+1 -1
View File
@@ -1,4 +1,4 @@
error[E0658]: specialization is unstable
error[E0658]: specialization is experimental
--> $DIR/track6.rs:LL:CC
|
LL | default fn bar() {}