I recently run into the somewhat obnoxious fact that if T: Drop
, then you can’t move out of public fields of T
(for obvious reasons). In the presence of a C++ ptr-to-member type this actually becomes really annoying, because there’s no way to write a function that takes a generic T
, a field offset over it, and uses it to move out of the T
with it:
// using syntax from my other post
fn move_out_of<T, U>(x: T, offset: T.U) -> U {
x.(offset)
// drop glue here
}
// .. imagine we're in liballoc
let x: Unique<i32> = move_out_of(Box::new(0), offsetof Box::<_>.0); // unsound!
It’s unclear if this is a problem, since we could, in principle, make T.U
unilaterally uninhabited if T: Drop
… but then we’re not allowed to do write this function, which is always sound:
fn ref_out_of<T, U>(x: &T, offset: T.U) -> &U {
&x.(offset)
// drop glue? what drop glue?
}
I think this problem can be solved completely without touching the compiler:
// in core::marker or whatever
pub unsafe auto trait NoDrop {}
impl<T: Drop> !NoDrop for T {}
I’m pretty sure implementing this trait manually is always UB. Of course, this trait needs to be turned into a lang item for the purposes of generic move, so you can write
fn move_out_of<T: NoDrop, U>(x: T, offset: T.U) -> U {
x.(offset)
}