11use crate :: ops:: { Deref , DerefMut , DerefPure } ;
22use crate :: ptr;
33
4- /// A wrapper to inhibit the compiler from automatically calling `T`’s destructor.
5- /// This wrapper is 0-cost.
4+ /// A wrapper to inhibit the compiler from automatically calling `T`’s
5+ /// destructor. This wrapper is 0-cost.
66///
77/// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
8- /// `T`, and is subject to the same layout optimizations as `T`. As a consequence,
9- /// it has *no effect* on the assumptions that the compiler makes about its
10- /// contents. For example, initializing a `ManuallyDrop<&mut T>` with [`mem::zeroed`]
11- /// is undefined behavior. If you need to handle uninitialized data, use
12- /// [`MaybeUninit<T>`] instead.
8+ /// `T`, and is subject to the same layout optimizations as `T`. As a
9+ /// consequence, it has *no effect* on the assumptions that the compiler makes
10+ /// about its contents. For example, initializing a `ManuallyDrop<&mut T>` with
11+ /// [`mem::zeroed`] is undefined behavior. If you need to handle uninitialized
12+ /// data, use [`MaybeUninit<T>`] instead.
1313///
14- /// Note that accessing the value inside a `ManuallyDrop<T>` is safe.
15- /// This means that a `ManuallyDrop<T>` whose content has been dropped must not
16- /// be exposed through a public safe API.
17- /// Correspondingly, `ManuallyDrop::drop` is unsafe.
14+ /// Note that accessing the value inside a `ManuallyDrop<T>` is safe. This means
15+ /// that a `ManuallyDrop<T>` whose content has been dropped must not be exposed
16+ /// through a public safe API. Correspondingly, `ManuallyDrop::drop` is unsafe.
1817///
19- /// # `ManuallyDrop` and drop order.
18+ /// # `ManuallyDrop` and drop order
2019///
2120/// Rust has a well-defined [drop order] of values. To make sure that fields or
2221/// locals are dropped in a specific order, reorder the declarations such that
@@ -40,9 +39,116 @@ use crate::ptr;
4039/// }
4140/// ```
4241///
42+ /// # Interaction with `Box`
43+ ///
44+ /// Currently, if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or
45+ /// contains a `Box` inside, then dropping the `T` followed by moving the
46+ /// `ManuallyDrop<T>` is [considered to be undefined
47+ /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
48+ /// That is, the following code causes undefined behavior:
49+ ///
50+ /// ```no_run
51+ /// use std::mem::ManuallyDrop;
52+ ///
53+ /// let mut x = ManuallyDrop::new(Box::new(42));
54+ /// unsafe {
55+ /// ManuallyDrop::drop(&mut x);
56+ /// }
57+ /// let y = x; // Undefined behavior!
58+ /// ```
59+ ///
60+ /// This is [likely to change in the
61+ /// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the
62+ /// meantime, consider using [`MaybeUninit`] instead.
63+ ///
64+ /// # Safety hazards when storing `ManuallyDrop` in a struct or an enum.
65+ ///
66+ /// Special care is needed when all of the conditions below are met:
67+ /// * A struct or enum contains a `ManuallyDrop`.
68+ /// * The `ManuallyDrop` is not inside a `union`.
69+ /// * The struct or enum is part of public API, or is stored in a struct or an
70+ /// enum that is part of public API.
71+ /// * There is code that drops the contents of the `ManuallyDrop` field, and
72+ /// this code is outside the struct or enum's `Drop` implementation.
73+ ///
74+ /// In particular, the following hazards may occur:
75+ ///
76+ /// #### Storing generic types
77+ ///
78+ /// If the `ManuallyDrop` contains a client-supplied generic type, the client
79+ /// might provide a `Box` as that type. This would cause undefined behavior when
80+ /// the struct or enum is later moved, as mentioned in the previous section. For
81+ /// example, the following code causes undefined behavior:
82+ ///
83+ /// ```no_run
84+ /// use std::mem::ManuallyDrop;
85+ ///
86+ /// pub struct BadOption<T> {
87+ /// // Invariant: Has been dropped iff `is_some` is false.
88+ /// value: ManuallyDrop<T>,
89+ /// is_some: bool,
90+ /// }
91+ /// impl<T> BadOption<T> {
92+ /// pub fn new(value: T) -> Self {
93+ /// Self { value: ManuallyDrop::new(value), is_some: true }
94+ /// }
95+ /// pub fn change_to_none(&mut self) {
96+ /// if self.is_some {
97+ /// self.is_some = false;
98+ /// unsafe {
99+ /// // SAFETY: `value` hasn't been dropped yet, as per the invariant
100+ /// // (This is actually unsound!)
101+ /// ManuallyDrop::drop(&mut self.value);
102+ /// }
103+ /// }
104+ /// }
105+ /// }
106+ ///
107+ /// // In another crate:
108+ ///
109+ /// let mut option = BadOption::new(Box::new(42));
110+ /// option.change_to_none();
111+ /// let option2 = option; // Undefined behavior!
112+ /// ```
113+ ///
114+ /// #### Deriving traits
115+ ///
116+ /// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on
117+ /// the struct or enum could be unsound, since the derived implementations of
118+ /// these traits would access the `ManuallyDrop` field. For example, the
119+ /// following code causes undefined behavior:
120+ ///
121+ /// ```no_run
122+ /// use std::mem::ManuallyDrop;
123+ ///
124+ /// // This derive is unsound in combination with the `ManuallyDrop::drop` call.
125+ /// #[derive(Debug)]
126+ /// pub struct Foo {
127+ /// value: ManuallyDrop<String>,
128+ /// }
129+ /// impl Foo {
130+ /// pub fn new() -> Self {
131+ /// let mut temp = Self {
132+ /// value: ManuallyDrop::new(String::from("Unsafe rust is hard."))
133+ /// };
134+ /// unsafe {
135+ /// // SAFETY: `value` hasn't been dropped yet.
136+ /// ManuallyDrop::drop(&mut temp.value);
137+ /// }
138+ /// temp
139+ /// }
140+ /// }
141+ ///
142+ /// // In another crate:
143+ ///
144+ /// let foo = Foo::new();
145+ /// println!("{:?}", foo); // Undefined behavior!
146+ /// ```
147+ ///
43148/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
44149/// [`mem::zeroed`]: crate::mem::zeroed
45150/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
151+ /// [`MaybeUninit`]: crate::mem::MaybeUninit
46152#[ stable( feature = "manually_drop" , since = "1.20.0" ) ]
47153#[ lang = "manually_drop" ]
48154#[ derive( Copy , Clone , Debug , Default , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
0 commit comments