Skip to content
Open
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
360 changes: 173 additions & 187 deletions compiler/rustc_ast_passes/src/feature_gate.rs

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,15 @@ impl<'a> Parser<'a> {
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 {
self.psess.gated_spans.gate(sym::min_specialization, span);
self.psess.gated_spans.ungate_last(sym::specialization, span);
}
Comment on lines +252 to +255
Copy link
Copy Markdown
Member Author

@fmease fmease Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is: Enabling feat specialization should imply min_specialization (the latter only supports the specialization of associated functions, not associated constants & types however). That's how the post-expansion feature gate already works (it visits the AST).

For the soft pre-expansion feature gate we basically want the same thing. However, I don't want to pass a param to the item parser that tells it if the item is meant to be free, associated or foreign. Instead, all 3 fn item kinds are now part of min_specialization from a pre-expansion perspective if they're marked default which is absolutely fine (default on free & foreign items gets rejected later on during AST validation).

We ungate specialization here since later in rustc_ast_passes::feature_gate, a span gated behind specialization requires feature(specialization) … which is undesirable for assoc fns ofc. Finally, in AST passes we allow feature(specialization) to unlock spans gated behind specialization and ones behind min_specialization. This leads to the desired semantics.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like some/all of this information should be a comment in the code?

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,
Expand Down Expand Up @@ -603,6 +608,7 @@ impl<'a> Parser<'a> {
fn parse_polarity(&mut self) -> ast::ImplPolarity {
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
if self.check(exp!(Bang)) && self.look_ahead(1, |t| t.can_begin_type()) {
self.psess.gated_spans.gate(sym::negative_impls, self.token.span);
self.bump(); // `!`
ast::ImplPolarity::Negative(self.prev_token.span)
} else {
Expand Down Expand Up @@ -1015,6 +1021,7 @@ impl<'a> Parser<'a> {
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)) {
Expand Down
7 changes: 0 additions & 7 deletions tests/ui/auto-traits/ungated-impl.rs

This file was deleted.

23 changes: 0 additions & 23 deletions tests/ui/auto-traits/ungated-impl.stderr

This file was deleted.

11 changes: 2 additions & 9 deletions tests/ui/feature-gates/feature-gate-auto-traits.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
// Test that default and negative trait implementations are gated by
// `auto_traits` feature gate
auto trait DummyAutoTrait {} //~ ERROR auto traits are experimental and possibly buggy

struct DummyStruct;

auto trait AutoDummyTrait {}
//~^ ERROR auto traits are experimental and possibly buggy

impl !AutoDummyTrait for DummyStruct {}
//~^ ERROR negative trait bounds are not fully implemented; use marker types for now
Copy link
Copy Markdown
Member Author

@fmease fmease Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A gate test for negative impls doesn't belong in a gate test file for auto traits. Likely a remnant of the time when negative impls and auto traits were part of the same feature, optin_builtin_traits.

pub unsafe auto trait AnotherAutoTrait {} //~ ERROR auto traits are experimental and possibly buggy

fn main() {}
16 changes: 8 additions & 8 deletions tests/ui/feature-gates/feature-gate-auto-traits.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
error[E0658]: auto traits are experimental and possibly buggy
--> $DIR/feature-gate-auto-traits.rs:6:1
--> $DIR/feature-gate-auto-traits.rs:1:1
|
LL | auto trait AutoDummyTrait {}
LL | auto trait DummyAutoTrait {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
= help: add `#![feature(auto_traits)]` 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]: negative trait bounds are not fully implemented; use marker types for now
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the marker types suggestion no longer true? That seems like useful information.

--> $DIR/feature-gate-auto-traits.rs:9:6
error[E0658]: auto traits are experimental and possibly buggy
--> $DIR/feature-gate-auto-traits.rs:3:1
|
LL | impl !AutoDummyTrait for DummyStruct {}
| ^^^^^^^^^^^^^^^
LL | pub unsafe auto trait AnotherAutoTrait {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information
= help: add `#![feature(negative_impls)]` to the crate attributes to enable
= note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
= help: add `#![feature(auto_traits)]` 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
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/feature-gates/soft-feature-gate-negative_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// For historical reasons, negative impls don'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-negative_impls.rs`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment confused me. Isn't this PR all about adding a proper pre-expansion feature gate? I guess it's not "proper" yet? I don't understand the difference.

Copy link
Copy Markdown
Member Author

@fmease fmease Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not "proper" yet as it's merely a warning for now (as backed by the MCP). Upgrading it to a hard error is the next step at some point in the future that's gonna be much harder to do (crater, fixing fallout downstream, T-lang nomination).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change "proper pre-expansion one" to "a pre-expansion hard error", or similar?

//@ check-pass

#[cfg(false)]
impl !Trait for () {}
//~^ WARN negative impls are experimental
//~| WARN unstable syntax can change at any point in the future

fn main() {}
14 changes: 14 additions & 0 deletions tests/ui/feature-gates/soft-feature-gate-negative_impls.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
warning: negative impls are experimental
--> $DIR/soft-feature-gate-negative_impls.rs:8:6
|
LL | impl !Trait for () {}
| ^
|
= note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information
= help: add `#![feature(negative_impls)]` 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: 1 warning emitted

20 changes: 10 additions & 10 deletions tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ error[E0405]: cannot find trait `r#use` in this scope
LL | fn binder() -> impl Sized + for<'a> use<> {}
| ^^^ not found in this scope

error[E0658]: const trait impls are experimental
--> $DIR/bound-modifiers.rs:12:32
|
LL | fn constness() -> impl Sized + const use<> {}
| ^^^^^
|
= 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]: `async` trait bounds are unstable
--> $DIR/bound-modifiers.rs:7:32
|
Expand All @@ -57,16 +67,6 @@ LL | fn asyncness() -> impl Sized + async use<> {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use the desugared name of the async trait, such as `AsyncFn`

error[E0658]: const trait impls are experimental
--> $DIR/bound-modifiers.rs:12:32
|
LL | fn constness() -> impl Sized + const use<> {}
| ^^^^^
|
= 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 10 previous errors

Some errors have detailed explanations: E0405, E0658.
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/macros/stringify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/ui/parser/trait-item-with-defaultness-pass.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ check-pass
#![feature(specialization)]

fn main() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ trait Foo {
fn foo(&self);
}

default impl<T> Foo for T { //~ ERROR specialization is unstable
default impl<T> Foo for T { //~ ERROR specialization is experimental
fn foo(&self) {}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0658]: specialization is unstable
error[E0658]: specialization is experimental
--> $DIR/specialization-feature-gate-default.rs:7:1
|
LL | / default impl<T> Foo for T {
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/specialization/feature-gate-specialization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// The gate for `default impl` is exercised in `defaultimpl/specialization-feature-gate-default.rs`.

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
}

fn main() {}
33 changes: 33 additions & 0 deletions tests/ui/specialization/feature-gate-specialization.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
error[E0658]: specialization is experimental
--> $DIR/feature-gate-specialization.rs:10: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:11: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:12: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: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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

Loading
Loading