Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Drop Elaboration

We know where drops may happen, so we now only need to decide which drops to run at each relevant program point.

Dropping happens in-place by running the compiler-generated core::ptr::drop_in_place function on the place to be dropped. Instead of calling that function directly we use the drop_in_place!() built-in macro so that the borrow-checker can tell that the place has been deinitialized.

In this step we'll replace every ensure_dropped!($place) with a series of appropriate calls to drop_in_place!($subplace).

For any subplace of $place that hasn't been explicitly moved out, we insert a call to drop_in_place!. This can require adding extra booleans ("drop flags") if different branches haven't moved the same places:

#![allow(unused)]
fn main() {
let x = Struct {
    a: String::new(),
    b: String::new(),
};
if foo() {
    drop(move!(x.a));
} else {
    drop(move!(x.b));
}
ensure_dropped!(x.a);
x.a = "some other string".to_owned();
ensure_dropped!(x);
scope_end!(x);

// becomes:
let a_is_initialized = true;
let b_is_initialized = true;
if foo() {
    drop(move!(x.a));
    a_is_initialized = false;
} else {
    drop(move!(x.b));
    b_is_initialized = false;
}
if a_is_initialized {
    drop_in_place!(x.a);
}
x.a = "some other string".to_owned();
if b_is_initialized {
    drop_in_place!(x.b);
}
drop_in_place!(x.a);
scope_end!(x);
}

(unwind paths omitted for legibility)

After this step, all the code involved in dropping values is explicit.