# Removal of `auto trait` in favor of `#[rustc_auto_trait]`
## Introduction
Auto traits are no longer intended to be stabilized and made available to the general public[^1].
They should remain solely an implementation detail of blessed libraries like `core` and `std`.
## Proposal
To reflect this new status of auto traits, I hereby propose to remove the syntax `auto trait` alongside the feature `auto_traits` it is gated behind and to introduce the attribute `#[rustc_auto_trait]` as part of the *internal* feature `rustc_attrs`.
```rust
#![feature(auto_traits)]
auto trait Trait {}
// ---->
#![feature(rustc_attrs)]
#![allow(internal_features)]
#[rustc_auto_trait]
trait Trait {}
```
## Motivation
It sends the wrong signals to have custom syntax for this, for all intents and purposes, *internal* feature. It may mislead end users to believe that auto traits will eventually be stabilized which is unlikely.
An internal attribute with an off-putting name like `rustc_auto_trait` should slowly steer users away from this feature. People who currently make use of auto traits in their projects will hopefully think twice about opting into `rustc_attrs` in order to continue using auto traits when they migrate to the latest nightly compiler and regard it only as a short-term solution if they do end up keeping their auto traits around.
Regarding the motivation to not stabilize the feature for others to use freely, I can't speak for T-lang but I can list the biggest pitfalls of auto traits. See [**Pitfalls of Auto Traits**](#Pitfalls-of-Auto-Traits).
Lastly, [it allows us to simplify the HIR](https://github.com/rust-lang/rust/pull/116126/commits/098bebc5628b30210edcd831ddad06d14bdaa75f).
## Drawbacks
* Obviously, experimental features don't come with stability guarantees. Still, in reality some users like to think that experimental features will generally be stabilized *someday* modulo some adjustments and use them anyway in their larger projects. For them this change would be quite disruptive and require them to potentially do a lot of non-trivial work to migrate away from auto traits causing churn in the ecosystem. See [**Affected Projects**](#Affected-Projects).
* Fully removing the syntax is a breaking change for *stable* users since `cfg`'ed out `auto trait`s successfully compile on stable as `auto_traits` uses a post-expansion feature gate due to historical reasons. Unfortunately, this is not a hypothetical, stable users of [leptos-rs/leptos](https://github.com/leptos-rs/leptos) and [Pyo3/pyo3](https://github.com/PyO3/pyo3) would be affected.
Note however that the plan is to keep parsing `auto trait` for now and to reject it after macro expansion which would solve this in the meantime. See [**Steps**](#Steps).
As a matter of fact, to this day we accept the original syntax of auto traits (or rather *opt-in built-in traits*) if it's `cfg`'ed out: `#[cfg(FALSE)] impl Trait for .. {}` which could be a warning to us.
* The following points are less about the proposed changes to the surface language and more about the notion of considering auto traits as *internal* only:
* With the prospect of auto traits being stabilized at some point gone, standard library traits like `Send`, `Sync`, `Unpin`, `UnwindSafe` and `RefUnwindSafe` may feel more “special” and more “exotic”.
* Auto traits might be essential or at least very nice to model certain problem domains (see [**Affected Projects**](#Affected-Projects)) and if so should be available to all users.
## Alternatives
* Don't do anything. This may lead to more and more users adapting and starting to rely on auto traits together with all of their *pitfalls* (see [**Pitfalls of Auto Traits**](#Pitfalls-of-Auto-Traits)).
* Keep the syntax but mark `auto_traits` as *internal*. This would lead to less churn in the ecosystem but it might not send a strong enough message to users already depending on auto traits (contrary to first-time users) since it's easier to silence the warning than to address it properly.
## Steps
1. [PR #116126][pr1]: Reject `auto trait` after macro expansion but *continue to parse* it which is necessary for bootstrapping. Introduce `#[rustc_auto_trait]` behind the `rustc_attrs` feature and remove the `auto_traits` feature.
2. [Issue #116121](iss): Emit a future-incompat warning for `auto trait` *before macro expansion* to successfully lint against `cfg`'ed out `auto trait`s etc.
3. After a set *grace period* which at the earliest starts after the next beta bump that occurs after the PR above has been merged, the syntax can be removed from the parser and the AST if at all possible (see [**Drawbacks**](#Drawbacks)).
[pr1]: https://github.com/rust-lang/rust/pull/116126
[iss]: https://github.com/rust-lang/rust/issues/116121
## Future Possibilities
It's always possible to move the status of the feature from *internal* back to *experimental* and change the attribute from `#[rustc_auto_trait]` to `#[auto_trait]`. We can also reintroduce the syntax `auto trait`. However, it's unclear how the macro fragment specifier `item` can then be updated without breaking backward compatibility. Generally, macro fragment specifiers are not forward compatible (see `inline_const` for example) which needs be solved at some point.
## Pitfalls of Auto Traits
* *Private* struct fields leak auto trait implementations into the public API
* Changing the type of a private field of a public ADT may accidentally result in the whole type not implementing a given auto trait which can break downstream users unbeknownst to the library author
* If the standard library is the only one allowed to define auto traits, the issue will persist but it will also be more manageable since end users can theoretically enumerate all auto traits in their head before changing the type of a field or use one of the many `assert_impls_auto_trait!(Ty, Tr0, Tr1, …)` helper macros available on crates.io to ensure that they don't introduce regressions.
If `auto_traits` was stabilized, it would be plain out impossible to do anything remotely similar since downstream users could define arbitrary amounts of auto traits together with negative implementations which the upstream user has not the slightest clue about.
* Opaque types like RPIT and TAIT leak auto trait implementations. This leads to a very similar situation as described above.
## Affected Projects
* [leptos-rs/leptos](https://github.com/leptos-rs/leptos) (11.9k stars)
* Behind feature flag `nightly`.
* [PyO3/pyo3](https://github.com/PyO3/pyo3) (9.4k stars)
* *Rust bindings for the Python interpreter*
* Employs a single auto trait `Ungil` behind the Cargo feature flag `nightly` to ensure memory safety.
* [enso-org/enso](https://github.com/enso-org/enso) (6.6k stars)
* *Not* behind a feature flag!
* [thepowersgang/rust_os](https://github.com/thepowersgang/rust_os) (666 stars)
* [multiversx/mx-sdk-rs](https://github.com/multiversx/mx-sdk-rs) (147 stars)
* [vE5li/korangar](https://github.com/vE5li/korangar) (51 stars)
* [tearust/sdk](https://github.com/tearust/sdk)
* [OSH-2022/x-QvQ](https://github.com/OSH-2022/x-QvQ)
* [waynexia/anchored](https://github.com/waynexia/anchored)
* [KomodoPlatform/komodo-defi-framework](https://github.com/KomodoPlatform/komodo-defi-framework)
There might be many more since the ones above are merely from the first few pages of the search results (GitHub Advanced Search / Code Search).
[^1]: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Removal.20of.20.60auto.20trait.60.20syntax/near/392487050