rustc_lint::tail_expr_drop_order

# Static TAIL_EXPR_DROP_ORDER

source

    pub static TAIL_EXPR_DROP_ORDER: &Lint

Expand description

The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type with a significant `Drop` implementation, such as locks. In case there are also local variables of type with significant `Drop` implementation as well, this lint warns you of a potential transposition in the drop order. Your discretion on the new drop order introduced by Edition 2024 is required.

#### §Example

ⓘ

    #![feature(shorter_tail_lifetimes)]
    #![warn(tail_expr_drop_order)]
    struct Droppy(i32);
    impl Droppy {
        fn get(&self) -> i32 {
            self.0
        }
    }
    impl Drop for Droppy {
        fn drop(&mut self) {
            // This is a custom destructor and it induces side-effects that is observable
            // especially when the drop order at a tail expression changes.
            println!("loud drop {}", self.0);
        }
    }
    fn edition_2024() -> i32 {
        let another_droppy = Droppy(0);
        Droppy(1).get()
    }
    fn main() {
        edition_2024();
    }

{{produces}}

#### §Explanation

In tail expression of blocks or function bodies, values of type with significant `Drop` implementation has an ill-specified drop order before Edition 2024 so that they are dropped only after dropping local variables. Edition 2024 introduces a new rule with drop orders for them, so that they are dropped first before dropping local variables.

A significant `Drop::drop` destructor here refers to an explicit, arbitrary implementation of the `Drop` trait on the type, with exceptions including `Vec`, `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise so long that the generic types have no significant destructor recursively. In other words, a type has a significant drop destructor when it has a `Drop` implementation or its destructor invokes a significant destructor on a type. Since we cannot completely reason about the change by just inspecting the existence of a significant destructor, this lint remains only a suggestion and is set to `allow` by default.

This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` does in Edition 2024. No fix will be proposed by this lint. However, the most probable fix is to hoist `Droppy` into its own local variable binding.

    struct Droppy(i32);
    impl Droppy {
        fn get(&self) -> i32 {
            self.0
        }
    }
    fn edition_2024() -> i32 {
        let value = Droppy(0);
        let another_droppy = Droppy(1);
        value.get()
    }