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
361 changes: 174 additions & 187 deletions compiler/rustc_ast_passes/src/feature_gate.rs

Large diffs are not rendered by default.

12 changes: 11 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,18 @@ 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 {
// 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);
}
Comment on lines +252 to +258
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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done

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 +611,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 +1024,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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Readded as proper diagnostic note

--> $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
6 changes: 3 additions & 3 deletions tests/ui/feature-gates/soft-feature-gate-auto_traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// For historical reasons, auto traits 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.
// For historical reasons, auto traits don't have an erroring pre-expansion feature gate.
// We're now at least issuing a warning for those that only exist before macro expansion.
// FIXME(#154045): Turn this pre-expansion warning into an error and remove the post-expansion gate.
// As part of this, move these test cases into `feature-gate-auto-traits.rs`.
//@ check-pass

Expand Down
6 changes: 3 additions & 3 deletions tests/ui/feature-gates/soft-feature-gate-box_patterns.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// For historical reasons, box patterns 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.
// For historical reasons, box patterns don't have an erroring pre-expansion feature gate.
// We're now at least issuing a warning for those that only exist before macro expansion.
// FIXME(#154045): Turn this pre-expansion warning into an error and remove the post-expansion gate.
// As part of this, move these test cases into `feature-gate-box_patterns.rs`.
//@ check-pass

Expand Down
6 changes: 3 additions & 3 deletions tests/ui/feature-gates/soft-feature-gate-decl_macro.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// For historical reasons, decl macros 2.0 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.
// For historical reasons, decl macros 2.0 don't have an erroring pre-expansion feature gate.
// We're now at least issuing a warning for those that only exist before macro expansion.
// FIXME(#154045): Turn this pre-expansion warning into an error and remove the post-expansion gate.
// As part of this, move these test cases into `feature-gate-decl_macro.rs`.
//@ check-pass

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 an erroring pre-expansion feature gate.
// We're now at least issuing a warning for those that only exist before macro expansion.
// FIXME(#154045): Turn this pre-expansion warning into an error and remove the post-expansion gate.
// 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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done

//@ 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

6 changes: 3 additions & 3 deletions tests/ui/feature-gates/soft-feature-gate-trait_alias.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// For historical reasons, trait aliases 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.
// For historical reasons, trait aliases don't have an erroring pre-expansion feature gate.
// We're now at least issuing a warning for those that only exist before macro expansion.
// FIXME(#154045): Turn this pre-expansion warning into an error and remove the post-expansion gate.
// As part of this, move these test cases into `feature-gate-trait-alias.rs`.
//@ check-pass

Expand Down
6 changes: 3 additions & 3 deletions tests/ui/feature-gates/soft-feature-gate-try_blocks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// For historical reasons, try blocks 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.
// For historical reasons, try blocks don't have an erroring pre-expansion feature gate.
// We're now at least issuing a warning for those that only exist before macro expansion.
// FIXME(#154045): Turn this pre-expansion warning into an error and remove the post-expansion gate.
// As part of this, move these test cases into `feature-gate-try_blocks.rs`.
//@ edition: 2018
//@ check-pass
Expand Down
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
21 changes: 21 additions & 0 deletions tests/ui/specialization/feature-gate-specialization.rs
Original file line number Diff line number Diff line change
@@ -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() {}
45 changes: 45 additions & 0 deletions tests/ui/specialization/feature-gate-specialization.stderr
Original file line number Diff line number Diff line change
@@ -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`.
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

Loading
Loading