Repository navigation
Tracking issue for rustc_reservation_impl attribute #64631
Description
Background
The #[rustc_reservation_impl] attribute was added as part of the effort to stabilize !. Its goal is to make it possible to add a impl<T> From<!> for T impl in the future by disallowing downstream crates to do negative reasoning that might conflict with that.
Warning: the effect of this attribute is quite subtle, and it should be used with caution! In particular, adding a "reservation impl" alone does not guarantee that one can add the impl in the future, as described below.
History
- Initial implementation in reserve
impl<T> From<!> for T#62661
Current blockers before this attribute can be used to affect end-users
- How should "reserved" impls show up in rustdoc? (How to handle reservation impls in rustdoc / error messages #64633)
- What should its error message be? (How to handle reservation impls in rustdoc / error messages #64633)
Usage
You can use the #[rustc_reservation_impl] attribute as follows:
#[rustc_reservation_impl]
impl<T> From<!> for T { .. }For the most part, rustc will act as though this impl does not exist. For example, users can add overlapping impls if they prefer:
struct LocalType1<T>(T);
impl<T> From<!> for LocalType1<T> { }
struct LocalType2<T>(T);
impl<T> From<T> for LocalType2<T> { }Note that this implies that the #[rustc_reservation_impl] attribute alone does not guarantee that you can add the reservation impl in a future compatible way. Adding the reserved impl in the future may still cause coherence overlap (e.g., the impl for LocalType<T> for the impl for all T would overlap here). This will typically result in errors.
In order to add the impl, you must be able to ensure that coherence will allow the overlapping impls. This can be done in two ways, both of which are presently unstable:
- Specialization: but be careful! e.g., the current specialization rules do not suffice in the
LocalType2example above, since neither impl is a subset of one another. - Marker traits: we have a notion of marker traits that are allowed to overlap. Marker traits currently must have no items, which excludes e.g.
From, but we could grow this definition.
What does the attribute do?
The attribute prevents negative reasoning. In particular, it forbids impls like this:
trait LocalTrait;
struct LocalType3;
impl<T> LocalTrait for T where T: From<!> { }
impl<T> LocalTrait for LocalType3 { }Without the reservation impl, this would be legal, because the crate may assume that LocalType: From<!> does not hold (since LocalType is local to the crate). With the reservation impl, however, code like this will get an error.
Activity
TY: skip impls with `rustc_reservation_impl` attribute while type inf…
TY: skip impls with `rustc_reservation_impl` attribute while type inf…
Merge #4688
nikomatsakis commentedon Jun 22, 2022
We visited this during lang team backlog bonanza. Conclusions:
!-- there could be a useful end-user feature of "reserving" space to add an impl later, but this feature permits people to add things that overlap the intended impl, because we wanted people to be able to addimpl From<!> for MyTypeeven though we couldn't yet add the blanket impl (can't remember why).!again.Auto merge of #14750 - lowr:fix/rustc_reservation_impl, r=HKalbasi
Pr0methean commentedon Jun 2, 2023
I say we should fix whatever's preventing the blanket impl. Implementations of a method that the compiler can prove is unreachable shouldn't be able to conflict with each other -- otherwise it'd be like making
CloneandDebugconflict just because they both don't implementkwyjibo(&self) -> (u32,u8,u8,u16,Result<Vec<u8>,Vec<()>>).clarfonthey commentedon Jun 5, 2026
Worth commenting that shockingly, I found a use case for this outside of just the never type in the standard library: bringing
ToOwnedintocore: #t-libs > core::borrow::Cow (cowcore)Effectively, it would allow saying "these impls for
coretypes will be defined in thealloccrate" without supercharging#[rustc_allow_incoherent_impl]to just tell the compiler to shut up on arbitrary trait/impl definitions, which would probably break the solver.My thought process is also that associated types would be treated as opaque for the sake of the solver, where the actual value of the type doesn't matter since the impls can't be used.
JonathanBrouwer commentedon Aug 18, 2026
For people looking into this, including my future self:
#160871 will remove this attribute after #160705 lands
@clarfonthey mentioned in #160871 (comment) that the current implementation of
#[rustc_allow_incoherent_impl]is not a good fit for their bringingToOwnedintocoreidea, so this is not a blockerRollup merge of rust-lang#160705 - WaffleLapkin:unreserve_Fromᐸǃᐳ, r=…
Rollup merge of rust-lang#160705 - WaffleLapkin:unreserve_Fromᐸǃᐳ, r=…
Rollup merge of rust-lang#160705 - WaffleLapkin:unreserve_Fromᐸǃᐳ, r=…
Unrolled build for #160705 in rollup 161672
Rollup merge of rust-lang#160871 - WaffleLapkin:remove_rustc_reservat…
Unrolled build for #160871 in rollup 161772
clarfonthey commentedon Aug 25, 2026
I'm not sure exactly where I should bring up that option for
allow_incoherent_implas a potential solution. A lot of them may just be replaced bybuild-stdeventually merging the libstd crates again.Rollup merge of #160871 - WaffleLapkin:remove_rustc_reservation_impl,…
Rollup merge of #160705 - WaffleLapkin:unreserve_Fromᐸǃᐳ, r=JonathanB…
Rollup merge of rust-lang#160871 - WaffleLapkin:remove_rustc_reservat…
Rollup merge of #160871 - WaffleLapkin:remove_rustc_reservation_impl,…