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///
1918/// # `ManuallyDrop` and drop order.
2019///
@@ -40,9 +39,114 @@ use crate::ptr;
4039/// }
4140/// ```
4241///
42+ /// # Interaction with `Box`.
43+ ///
44+ /// Currently, once the `Box<T>` inside a `ManuallyDrop<Box<T>>` is dropped,
45+ /// moving the `ManuallyDrop<Box<T>>` is [considered to be undefined
46+ /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
47+ /// That is, the following code causes undefined behavior:
48+ ///
49+ /// ```no_run
50+ /// use std::mem::ManuallyDrop;
51+ ///
52+ /// let mut x = ManuallyDrop::new(Box::new(42));
53+ /// unsafe {
54+ /// ManuallyDrop::drop(&mut x);
55+ /// }
56+ /// let y = x; // Undefined behavior!
57+ /// ```
58+ ///
59+ /// This may change in the future. In the meantime, consider using
60+ /// [`MaybeUninit`] instead.
61+ ///
62+ /// # Safety hazards when storing `ManuallyDrop` in a struct / enum.
63+ ///
64+ /// Special care is needed when all of the conditions below are met:
65+ /// * A field of a struct or enum is a `ManuallyDrop` or contains a
66+ /// `ManuallyDrop`, without the `ManuallyDrop` being inside a `union`.
67+ /// * The struct or enum is part of public API, or is stored in a struct or enum
68+ /// that is part of public API.
69+ /// * There is code outside of a `Drop` implementation that calls
70+ /// [`ManuallyDrop::drop`] or [`ManuallyDrop::take`] on the `ManuallyDrop`
71+ /// field.
72+ ///
73+ /// In particular, the following hazards can occur:
74+ ///
75+ /// #### Storing generic types
76+ ///
77+ /// If the `ManuallyDrop` contains a client-supplied generic type, the client
78+ /// might provide a `Box`, causing undefined behavior when the struct / enum is
79+ /// later moved, as mentioned above. For example, the following code causes
80+ /// undefined behavior:
81+ ///
82+ /// ```no_run
83+ /// use std::mem::ManuallyDrop;
84+ ///
85+ /// pub struct BadOption<T> {
86+ /// // Invariant: Has been dropped iff `is_some` is false.
87+ /// value: ManuallyDrop<T>,
88+ /// is_some: bool,
89+ /// }
90+ /// impl<T> BadOption<T> {
91+ /// pub fn new(value: T) -> Self {
92+ /// Self { value: ManuallyDrop::new(value), is_some: true }
93+ /// }
94+ /// pub fn change_to_none(&mut self) {
95+ /// if self.is_some {
96+ /// self.is_some = false;
97+ /// unsafe {
98+ /// // SAFETY: `value` hasn't been dropped yet, as per the invariant
99+ /// // (This is actually unsound!)
100+ /// ManuallyDrop::drop(&mut self.value);
101+ /// }
102+ /// }
103+ /// }
104+ /// }
105+ ///
106+ /// // In another crate:
107+ ///
108+ /// let mut option = BadOption::new(Box::new(42));
109+ /// option.change_to_none();
110+ /// let option2 = option; // Undefined behavior!
111+ /// ```
112+ ///
113+ /// #### Deriving traits
114+ ///
115+ /// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on
116+ /// the struct / enum could be unsound, since the derived implementations of
117+ /// these traits would access the `ManuallyDrop` field. For example, the
118+ /// following code causes undefined behavior:
119+ ///
120+ /// ```no_run
121+ /// use std::mem::ManuallyDrop;
122+ ///
123+ /// #[derive(Debug)] // This is unsound!
124+ /// pub struct Foo {
125+ /// value: ManuallyDrop<String>,
126+ /// }
127+ /// impl Foo {
128+ /// pub fn new() -> Self {
129+ /// let mut temp = Self {
130+ /// value: ManuallyDrop::new(String::from("Unsafe rust is hard"))
131+ /// };
132+ /// unsafe {
133+ /// // SAFETY: `value` hasn't been dropped yet.
134+ /// ManuallyDrop::drop(&mut temp.value);
135+ /// }
136+ /// temp
137+ /// }
138+ /// }
139+ ///
140+ /// // In another crate:
141+ ///
142+ /// let foo = Foo::new();
143+ /// println!("{:?}", foo); // Undefined behavior!
144+ /// ```
145+ ///
43146/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
44147/// [`mem::zeroed`]: crate::mem::zeroed
45148/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
149+ /// [`MaybeUninit`]: crate::mem::MaybeUninit
46150#[ stable( feature = "manually_drop" , since = "1.20.0" ) ]
47151#[ lang = "manually_drop" ]
48152#[ derive( Copy , Clone , Debug , Default , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
0 commit comments