Attention Hackers: Filling Drop

Ah, I overlooked a problem that was exposed during my attempt to prototype this handling of #[unsafe_no_drop_flag].

While I do believe one can skip the zeroing/filling after the destructor runs for a struct with #[unsafe_no_drop_flag] (assuming its destructor has been written accordingly to ensure resources are cleaned up only once), there is another case where zeroing/filling is done currently in the generated code: When you move a value out of one location into another, we fill the original location with zeroes today (and with DONE_DROP tomorrow) so that we do not run the destructor at all when we hit the end of the scope for the original location.

I had not really thought carefully about this before; certainly if we are going to support #[unsafe_no_drop_flag] in any proper form, we need to actually provide the means for structs to customize how those moves are handled.

E.g. I am currently thinking maybe a second method on Drop, perhaps named forget, with an inlined empty default implementation, that structs with #[unsafe_no_drop_flag] are expected to implement. And then a move such a let b = a; would also call a.forget().

So for example one might have:

#[unsafe_no_drop_flag]
pub struct Vec<T> { ptr: Unique<T>, len: usize, cap: usize }

impl<T> Drop for Vec<T> {
    fn forget(&mut self) {
        // a zero capacity indicates no work to do
        self.cap = 0;
    }
    fn drop(&mut self) {
        // a zero capacity indicates no work to do
        if self.cap != 0 {
            unsafe {
                for x in &*self {
                    ptr::read(x);
                }
                dealloc(*self.ptr, self.cap)
            }
            self.cap = 0;
        }
    }
}


(Or maybe we should just remove support for #[unsafe_no_drop_flag] entirely; it becomes harder to justify supporting it with stack-local drop flags.)