Home Explore Blog CI



rustc

1st chunk of `src/borrow_check/drop_check.md`
19dab593e76b73e450106eeb6064d2a32d425dbf464eb1cb0000000100000c75
# Drop Check

We generally require the type of locals to be well-formed whenever the
local is used. This includes proving the where-bounds of the local and
also requires all regions used by it to be live.

The only exception to this is when implicitly dropping values when they
go out of scope. This does not necessarily require the value to be live:

```rust
fn main() {
    let x = vec![];
    {
        let y = String::from("I am temporary");
        x.push(&y);
    }
    // `x` goes out of scope here, after the reference to `y`
    // is invalidated. This means that while dropping `x` its type
    // is not well-formed as it contain regions which are not live.
}
```

This is only sound if dropping the value does not try to access any dead
region. We check this by requiring the type of the value to be
drop-live.
The requirements for which are computed in `fn dropck_outlives`.

The rest of this section uses the following type definition for a type
which requires its region parameter to be live:

```rust
struct PrintOnDrop<'a>(&'a str);
impl<'a> Drop for PrintOnDrop<'_> {
    fn drop(&mut self) {
        println!("{}", self.0);
    }
}
```

## How values are dropped

At its core, a value of type `T` is dropped by executing its "drop
glue". Drop glue is compiler generated and first calls `<T as
Drop>::drop` and then recursively calls the drop glue of any recursively
owned values.

- If `T` has an explicit `Drop` impl, call `<T as Drop>::drop`.
- Regardless of whether `T` implements `Drop`, recurse into all values
  *owned* by `T`:
    - references, raw pointers, function pointers, function items, trait
      objects[^traitobj], and scalars do not own anything.
    - tuples, slices, and arrays consider their elements to be owned.
      For arrays of length zero we do not own any value of the element
      type.
    - all fields (of all variants) of ADTs are considered owned. We
      consider all variants for enums. The exception here is
      `ManuallyDrop<U>` which is not considered to own `U`.
      `PhantomData<U>` also does not own anything.
      closures and generators own their captured upvars.

Whether a type has drop glue is returned by [`fn
Ty::needs_drop`](https://github.com/rust-lang/rust/blob/320b412f9c55bf480d26276ff0ab480e4ecb29c0/compiler/rustc_middle/src/ty/util.rs#L1086-L1108).

### Partially dropping a local

For types which do not implement `Drop` themselves, we can also
partially move parts of the value before dropping the rest. In this case
only the drop glue for the not-yet moved values is called, e.g.

```rust
fn main() {
    let mut x = (PrintOnDrop("third"), PrintOnDrop("first"));
    drop(x.1);
    println!("second")
}
```

During MIR building we assume that a local may get dropped whenever it
goes out of scope *as long as its type needs drop*. Computing the exact
drop glue for a variable happens **after** borrowck in the
`ElaborateDrops` pass. This means that even if some part of the local
have been dropped previously, dropck still requires this value to be
live. This is the case even if we completely moved a local.

```rust
fn main() {
    let mut x;
    {
        let temp = String::from("I am temporary");

Title: Drop Check and How Values are Dropped in Rust
Summary
This section explains the drop check mechanism in Rust, focusing on how values are dropped and the concept of drop glue. It details the circumstances under which types are considered 'drop-live' and the steps involved in dropping a value, including the handling of owned values within complex types. It also describes the concept of partially dropping local variables for types that do not implement the Drop trait, where only the drop glue for the remaining fields are called.