Description
The following is not valid:
fn cast<T: ?Sized, U: ?Sized>(t: *mut T) -> *mut U {
t as *mut U
}
Rust isn't able to guarantee that T
and U
have the same "vtable kinds", and thus isn't able to prove that *mut T
and *mut U
have compatible pointer metadata. We currently work around this using this method on KnownLayout
:
Line 731 in 0fae530
This has a limitation: It can't be called in a const
context.
Instead, we could make casting unsafe, requiring the caller to promise to ensure that the pointers are either both thin or both fat, and use a union-transmute under the hood to avoid the vtable problem:
/// # Safety
///
/// The caller must ensure that `Src` and `Dst` must either both be `Sized` or
/// both be unsized.
const unsafe fn cast_unchecked<Src: ?Sized, Dst: ?Sized>(src: *mut Src) -> *mut Dst {
#[repr(C)]
union Transmute<Src: Copy, Dst: Copy> {
src: Src,
dst: Dst,
}
unsafe { Transmute { src }.dst }
}
The behavior of this union-transmute is almost well-defined, but not quite. The Reference guarantees the behavior of raw pointer casts, but makes no guarantee that the equivalent transmute has the same behavior as a cast. I've put up a PR to guarantee that this is well-defined: rust-lang/reference#1661