arbitrary_self_types + derive_coerce_pointee allows calling methods whose where clauses are violated · Issue #136702 · rust-lang/rust (original) (raw)
Here's an example by @steffahn:
#![forbid(unsafe_code)] #![feature(arbitrary_self_types, derive_coerce_pointee)]
use std::any::TypeId; use std:📑:CoercePointee; use std:📑:PhantomData;
#[derive(CoercePointee)] #[repr(transparent)] struct SelfPtr<T: ?Sized>(*const T);
impl<T: ?Sized> std::ops::Deref for SelfPtr {
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) -> TypeId where Self: 'static; }
impl<T: ?Sized> GetTypeId for PhantomData { fn get_type_id(self: SelfPtr) -> TypeId where Self: 'static, { TypeId::of::() } }
// no T: 'static
bound 🐈⬛ necessary
fn type_id_of<T: ?Sized>() -> TypeId {
SelfPtr(&PhantomData:: as *const (dyn GetTypeId + ') as *const (dyn GetTypeId + 'static)).get_type_id()
}
fn type_id_of_val<T: ?Sized>(: &T) -> TypeId {
type_id_of::()
}
fn main() { let mut x = 1234; let reference = &mut x; let tid_of_ref = type_id_of_val(&reference); let closure = || *reference += 1; let tid_of_closure = type_id_of_val(&closure); dbg!(tid_of_ref, tid_of_closure); }
The double as *const dyn GetTypeId as *const dyn GetTypeId
is necessary; the second as
changes the lifetime something short-lived to 'static
. That means we call get_type_id
on a type that does not satisfy Self: 'static
.
@BoxyUwU has a similar example:
#![feature(arbitrary_self_types, derive_coerce_pointee)]
use std:📑:CoercePointee;
#[derive(CoercePointee)] #[repr(transparent)] struct MyPtr<T: ?Sized>(*const T);
use std::ops::Receiver;
impl<T: ?Sized> Receiver for MyPtr { type Target = T; }
trait Trait { fn foo(self: MyPtr) where Self: Send; }
impl Trait for *mut () { fn foo(self: MyPtr) { unreachable!() } }
fn main() { let a = 0x1 as *const *mut (); let a = a as *const dyn Trait as *const (dyn Trait + Send); MyPtr(a).foo(); }
Boxy's example is mitigated by a FCW lint. However, the lifetime example doesn't trigger a lint, and while the code above is "fine", we should at least have a good idea for why this cannot cause UB in other ways. (My gut feeling is that this can cause UB but I haven't tried.)
Cc @rust-lang/types