@@ -43,24 +43,6 @@ use crate::ptr;
4343/// }
4444/// ```
4545///
46- /// # Interaction with `Box`
47- ///
48- /// Currently, if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or
49- /// contains a `Box` inside, then dropping the `T` followed by moving the
50- /// `ManuallyDrop<T>` is [considered to be undefined
51- /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
52- /// That is, the following code causes undefined behavior:
53- ///
54- /// ```no_run
55- /// use std::mem::ManuallyDrop;
56- ///
57- /// let mut x = ManuallyDrop::new(Box::new(42));
58- /// unsafe {
59- /// ManuallyDrop::drop(&mut x);
60- /// }
61- /// let y = x; // Undefined behavior!
62- /// ```
63- ///
6446/// This is [likely to change in the
6547/// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the
6648/// meantime, consider using [`MaybeUninit`] instead.
@@ -75,14 +57,59 @@ use crate::ptr;
7557/// * There is code that drops the contents of the `ManuallyDrop` field, and
7658/// this code is outside the struct or enum's `Drop` implementation.
7759///
78- /// In particular, the following hazards may occur:
60+ /// In particular, deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`,
61+ /// or `Hash` on the struct or enum could be unsound, since the derived
62+ /// implementations of these traits would access the `ManuallyDrop` field. For
63+ /// example, the following code causes undefined behavior:
7964///
80- /// #### Storing generic types
65+ /// ```no_run
66+ /// use std::mem::ManuallyDrop;
8167///
82- /// If the `ManuallyDrop` contains a client-supplied generic type, the client
83- /// might provide a `Box` as that type. This would cause undefined behavior when
84- /// the struct or enum is later moved, as mentioned in the previous section. For
85- /// example, the following code causes undefined behavior:
68+ /// // This derive is unsound in combination with the `ManuallyDrop::drop` call.
69+ /// #[derive(Debug)]
70+ /// pub struct Foo {
71+ /// value: ManuallyDrop<String>,
72+ /// }
73+ /// impl Foo {
74+ /// pub fn new() -> Self {
75+ /// let mut temp = Self {
76+ /// value: ManuallyDrop::new(String::from("Unsafe rust is hard."))
77+ /// };
78+ /// unsafe {
79+ /// // SAFETY: `value` hasn't been dropped yet.
80+ /// ManuallyDrop::drop(&mut temp.value);
81+ /// }
82+ /// temp
83+ /// }
84+ /// }
85+ ///
86+ /// // In another crate:
87+ ///
88+ /// let foo = Foo::new();
89+ /// println!("{:?}", foo); // Undefined behavior!
90+ /// ```
91+ ///
92+ /// # Pre-`1.96` Interaction with `Box`
93+ ///
94+ /// Before Rust `1.96.0`, if you had a `ManuallyDrop<T>`, where the type `T`
95+ /// was a `Box` or contained a `Box` inside, then dropping the `T` followed by
96+ /// moving the `ManuallyDrop<T>` was [considered to be undefined
97+ /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
98+ /// That is, the following code caused undefined behavior:
99+ ///
100+ /// ```no_run
101+ /// use std::mem::ManuallyDrop;
102+ ///
103+ /// let mut x = ManuallyDrop::new(Box::new(42));
104+ /// unsafe {
105+ /// ManuallyDrop::drop(&mut x);
106+ /// }
107+ /// let y = x; // Undefined behavior! (pre 1.96.0)
108+ /// ```
109+ ///
110+ /// Note that this could also have happen with a generic type where the user of
111+ /// the library providing it could substitute the generic for a `Box<_>` and
112+ /// then move the library type:
86113///
87114/// ```no_run
88115/// use std::mem::ManuallyDrop;
@@ -101,7 +128,7 @@ use crate::ptr;
101128/// self.is_some = false;
102129/// unsafe {
103130/// // SAFETY: `value` hasn't been dropped yet, as per the invariant
104- /// // (This is actually unsound!)
131+ /// // (This is actually unsound pre rust 1.96.0 !)
105132/// ManuallyDrop::drop(&mut self.value);
106133/// }
107134/// }
@@ -112,41 +139,7 @@ use crate::ptr;
112139///
113140/// let mut option = BadOption::new(Box::new(42));
114141/// option.change_to_none();
115- /// let option2 = option; // Undefined behavior!
116- /// ```
117- ///
118- /// #### Deriving traits
119- ///
120- /// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on
121- /// the struct or enum could be unsound, since the derived implementations of
122- /// these traits would access the `ManuallyDrop` field. For example, the
123- /// following code causes undefined behavior:
124- ///
125- /// ```no_run
126- /// use std::mem::ManuallyDrop;
127- ///
128- /// // This derive is unsound in combination with the `ManuallyDrop::drop` call.
129- /// #[derive(Debug)]
130- /// pub struct Foo {
131- /// value: ManuallyDrop<String>,
132- /// }
133- /// impl Foo {
134- /// pub fn new() -> Self {
135- /// let mut temp = Self {
136- /// value: ManuallyDrop::new(String::from("Unsafe rust is hard."))
137- /// };
138- /// unsafe {
139- /// // SAFETY: `value` hasn't been dropped yet.
140- /// ManuallyDrop::drop(&mut temp.value);
141- /// }
142- /// temp
143- /// }
144- /// }
145- ///
146- /// // In another crate:
147- ///
148- /// let foo = Foo::new();
149- /// println!("{:?}", foo); // Undefined behavior!
142+ /// let option2 = option; // Undefined behavior! (pre 1.96)
150143/// ```
151144///
152145/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
0 commit comments