Proposal
Currently, Drop in rust is always by-reference - the object still needs to be valid for drop-glue after the call to Drop::drop
. An elegant way to fix this is to add a trait (e.g. Destruct
):
#[lang="destruct"]
pub trait Destruct {
fn destroy(self) {
// This isn't really legal Rust, but the "implicit"
// impl should be this.
<Drop as Self>::drop(&mut self);
let Self { .. } = self;
}
}
The trait should work like Drop
, except that you can destructure self on objects
that have it (of course, to avoid infinite recursion, the implementation of destroy
has to eventually destructure or leak self
).
Privacy Issues
Currently, in Rust, you can destructure a destructor-less object, even if it has private fields:
pub mod m { pub struct S(u32); }
mod b { use m::S; pub fn foo(s: S) { let S { .. } = s; } }
This is problematic with Destroy
, because other modules can call this, and
lose the structure without calling the destructor. The problem is avoided with
Drop
by preventing all destructuring, which basically breaks Destroy
(unless
you do a manual destructuring by getting a raw pointer to self
,
ptr::read
-ing all fields, and then forgetting self
, but this is quite ugly).
To allow for sane usage of Destroy
, we can either force destructuring of a type
with an explicit Destroy
impl to mention all fields, or just forbid destructuring
of types with an explicit Destroy
impl and inaccessible (because of privacy) fields.
Misc. Details
The same destructor-lifetime rules that apply to impls of Drop
should also apply to impls of Destroy
. A single type implementing both Drop
and Destroy
shall cause a compile-time error, as if there was an impl<T:â Drop> Destroy for T
.
Currently, the trait Destroy
isnât object-safe, as it has a by-value self
. However,
vtables (for Box<Trait>
) need to have a way to call it. Because of ABI issues, this could require a shim. We already have a drop-glue shim, through, so we can just adapt it.
Issues
I donât like the solutions to field privacy. If we have proper DST, we need to
add a nice way to call the destructor by-value (maybe add a fn destroy<T: ?Sized>(t: *mut T)
that explicitly calls the drop-glue?)