Skip to content

Conversation

@BoxyUwU
Copy link

@BoxyUwU BoxyUwU commented Dec 4, 2025

Hi there o/

I'm a member of the Rust Language's Types Team; as part of stabilizing the arbitrary_self_types and derive_coerce_pointee features we are changing what raw pointer casts are legal (rust-lang/rust#136702). Specifically, casting *const dyn Trait + 'a to *const dyn Trait + 'b where it is not able to be proven that 'a outlives 'b will become an error.

Without going into too much detail, the justification for this change is that casting trait object's lifetime bound to a lifetime that lives for a longer time could invalidate the VTable of the trait object, allowing for dispatching to methods that should not be callable. See this example from the linked issue:

#![forbid(unsafe_code)]
#![feature(arbitrary_self_types, derive_coerce_pointee)]

use std::any::TypeId;
use std::marker::{CoercePointee, PhantomData};

#[derive(CoercePointee)]
#[repr(transparent)]
struct SelfPtr<T: ?Sized>(*const T);

impl<T: ?Sized> std::ops::Deref for SelfPtr<T> {
    type Target = T;
    fn deref(&self) -> &T {
        panic!("please don't call me, I just want the `Receiver` impl!");
    }
}

trait GetTypeId {
    fn get_type_id(self: SelfPtr<Self>) -> TypeId
    where
        Self: 'static;
}

impl<T: ?Sized> GetTypeId for PhantomData<T> {
    fn get_type_id(self: SelfPtr<Self>) -> TypeId
    where
        Self: 'static,
    {
        TypeId::of::<T>()
    }
}

// no `T: 'static` bound necessary
fn type_id_of<T: ?Sized>() -> TypeId {
    let ptr = SelfPtr(
        &PhantomData::<T> as *const (dyn GetTypeId + '_) as *const (dyn GetTypeId + 'static),
    );
    ptr.get_type_id()
}

Unfortunately, going through the usual "future compatibility warning" process turned out to not be possible as checking lifetime constraints without emitting an error is prohibitively difficult to do in the implementation of the borrow checker. This means that you will never receive an FCW and its associated grace period to update your code to be compatible with the new rules.

I have attempted to update your codebase to the new rules for you so that it will still compile when we make this change. I hope this breakage won't cause you too much trouble and that you might even find the post-migration code to be better than how it was previously :-)

If you have any questions about why this change is required please let me know and I'll do my best to further explain the justification.


It wasn't clear to me if the pointer casts here were supposed to be implicitly casting the lifetimes of the trait object to 'static. This is currently happening because writing *mut dyn Trait in the return type of a function signature desguars to *mut dyn Trait + 'static, with this change we now write *mut dyn Trait + '_ which introduces a new lifetime parameter.

@UxuginPython
Copy link
Owner

Hello! Thank you for your pull request. To be honest this is a bit over my head, and if you would be willing to answer a few questions, that would be great.

  1. I thought the compiler treated all raw pointers as though they were 'static and that it's the user's responsibility to ensure that problems like with the vtables don't occur. However, this issue appears to involve raw pointers with lifetimes. What exactly is *const dyn Trait + 'a and how is it different from &'a dyn Trait and plain *const dyn Trait? Looking into this, I found this answer indicating that trait objects have their own lifetimes, but why is this and what does it entail?
  2. Why isn't the change occurring with 2027 Edition?
  3. A bit more practically, is there a toolchain I can install with the error implemented? The current nightly (ba86c0460 2025-12-06) still builds the existing code with any combination of the features you mentioned enabled.
  4. Approximately when do you expect the error to hit stable?

I'd love to merge and get this resolved if I could get a bit more clarity on the issue it fixes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants