Skip to content

Commit 60b102d

Browse files
committedSep 21, 2020
Don't recommend ManuallyDrop to customize drop order
See https://internals.rust-lang.org/t/need-for-controlling-drop-order-of-fields/12914/21 for the discussion. TL;DR: ManuallyDrop is unsafe and footguny, but you can just ask the compiler to do all the work for you by re-ordering declarations.
1 parent 6c44bcc commit 60b102d

File tree

1 file changed

+19
-36
lines changed

1 file changed

+19
-36
lines changed
 

‎library/core/src/mem/manually_drop.rs

+19-36
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,33 @@ use crate::ptr;
1515
/// be exposed through a public safe API.
1616
/// Correspondingly, `ManuallyDrop::drop` is unsafe.
1717
///
18-
/// # Examples
18+
/// # `ManuallyDrop` and drop order.
1919
///
20-
/// This wrapper can be used to enforce a particular drop order on fields, regardless
21-
/// of how they are defined in the struct:
20+
/// Rust has a well-defined [drop order] of values. To make sure that fields or
21+
/// locals are dropped in a specific order, reorder the declarations such that
22+
/// the implicit drop order is the correct one.
2223
///
23-
/// ```rust
24-
/// use std::mem::ManuallyDrop;
25-
/// struct Peach;
26-
/// struct Banana;
27-
/// struct Melon;
28-
/// struct FruitBox {
29-
/// // Immediately clear there’s something non-trivial going on with these fields.
30-
/// peach: ManuallyDrop<Peach>,
31-
/// melon: Melon, // Field that’s independent of the other two.
32-
/// banana: ManuallyDrop<Banana>,
33-
/// }
24+
/// It is possible to use `ManuallyDrop` to control the drop order, but this
25+
/// requires unsafe code and is hard to do correctly in the presence of
26+
/// unwinding.
3427
///
35-
/// impl Drop for FruitBox {
36-
/// fn drop(&mut self) {
37-
/// unsafe {
38-
/// // Explicit ordering in which field destructors are run specified in the intuitive
39-
/// // location – the destructor of the structure containing the fields.
40-
/// // Moreover, one can now reorder fields within the struct however much they want.
41-
/// ManuallyDrop::drop(&mut self.peach);
42-
/// ManuallyDrop::drop(&mut self.banana);
43-
/// }
44-
/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
45-
/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
46-
/// }
47-
/// }
48-
/// ```
28+
/// For example, if you want to make sure that a specific field is dropped after
29+
/// the others, make it the last field of a struct:
4930
///
50-
/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
51-
/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
52-
/// would also be leaked.
31+
/// ```
32+
/// struct Context;
5333
///
54-
/// In contrast, the automatically-generated compiler drop implementation would have ensured
55-
/// that all fields are dropped even in the presence of panics. This is especially important when
56-
/// working with [pinned] data, where reusing the memory without calling the destructor could lead
57-
/// to Undefined Behaviour.
34+
/// struct Widget {
35+
/// children: Vec<Widget>,
36+
/// // `context` will be dropped after `children`.
37+
/// // Rust guarantees that fields are dropped in the order of declaration.
38+
/// context: Context,
39+
/// }
40+
/// ```
5841
///
42+
/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
5943
/// [`mem::zeroed`]: crate::mem::zeroed
6044
/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
61-
/// [pinned]: crate::pin
6245
#[stable(feature = "manually_drop", since = "1.20.0")]
6346
#[lang = "manually_drop"]
6447
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]

0 commit comments

Comments
 (0)
Please sign in to comment.