@@ -57,56 +57,14 @@ use crate::ptr;
5757/// * There is code that drops the contents of the `ManuallyDrop` field, and
5858/// this code is outside the struct or enum's `Drop` implementation.
5959///
60- /// In particular, the following hazards may occur:
61- ///
62- /// #### Storing generic types
63- ///
64- /// If the `ManuallyDrop` contains a client-supplied generic type, the client
65- /// might provide a `Box` as that type. This would cause undefined behavior when
66- /// the struct or enum is later moved, as mentioned in the previous section. For
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
6763/// example, the following code causes undefined behavior:
6864///
6965/// ```no_run
7066/// use std::mem::ManuallyDrop;
7167///
72- /// pub struct BadOption<T> {
73- /// // Invariant: Has been dropped if `is_some` is false.
74- /// value: ManuallyDrop<T>,
75- /// is_some: bool,
76- /// }
77- /// impl<T> BadOption<T> {
78- /// pub fn new(value: T) -> Self {
79- /// Self { value: ManuallyDrop::new(value), is_some: true }
80- /// }
81- /// pub fn change_to_none(&mut self) {
82- /// if self.is_some {
83- /// self.is_some = false;
84- /// unsafe {
85- /// // SAFETY: `value` hasn't been dropped yet, as per the invariant
86- /// // (This is actually unsound!)
87- /// ManuallyDrop::drop(&mut self.value);
88- /// }
89- /// }
90- /// }
91- /// }
92- ///
93- /// // In another crate:
94- ///
95- /// let mut option = BadOption::new(Box::new(42));
96- /// option.change_to_none();
97- /// let option2 = option; // Undefined behavior!
98- /// ```
99- ///
100- /// #### Deriving traits
101- ///
102- /// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on
103- /// the struct or enum could be unsound, since the derived implementations of
104- /// these traits would access the `ManuallyDrop` field. For example, the
105- /// following code causes undefined behavior:
106- ///
107- /// ```no_run
108- /// use std::mem::ManuallyDrop;
109- ///
11068/// // This derive is unsound in combination with the `ManuallyDrop::drop` call.
11169/// #[derive(Debug)]
11270/// pub struct Foo {
@@ -131,13 +89,13 @@ use crate::ptr;
13189/// println!("{:?}", foo); // Undefined behavior!
13290/// ```
13391///
134- /// # Interaction with `Box`
92+ /// # Pre-`1.96` Interaction with `Box`
13593///
136- /// Currently , if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or
137- /// contains a `Box` inside, then dropping the `T` followed by moving the
138- /// `ManuallyDrop<T>` is [considered to be undefined
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
13997/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
140- /// That is, the following code causes undefined behavior:
98+ /// That is, the following code caused undefined behavior:
14199///
142100/// ```no_run
143101/// use std::mem::ManuallyDrop;
@@ -146,7 +104,42 @@ use crate::ptr;
146104/// unsafe {
147105/// ManuallyDrop::drop(&mut x);
148106/// }
149- /// let y = x; // Undefined behavior!
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:
113+ ///
114+ /// ```no_run
115+ /// use std::mem::ManuallyDrop;
116+ ///
117+ /// pub struct BadOption<T> {
118+ /// // Invariant: Has been dropped if `is_some` is false.
119+ /// value: ManuallyDrop<T>,
120+ /// is_some: bool,
121+ /// }
122+ /// impl<T> BadOption<T> {
123+ /// pub fn new(value: T) -> Self {
124+ /// Self { value: ManuallyDrop::new(value), is_some: true }
125+ /// }
126+ /// pub fn change_to_none(&mut self) {
127+ /// if self.is_some {
128+ /// self.is_some = false;
129+ /// unsafe {
130+ /// // SAFETY: `value` hasn't been dropped yet, as per the invariant
131+ /// // (This is actually unsound pre rust 1.96.0!)
132+ /// ManuallyDrop::drop(&mut self.value);
133+ /// }
134+ /// }
135+ /// }
136+ /// }
137+ ///
138+ /// // In another crate:
139+ ///
140+ /// let mut option = BadOption::new(Box::new(42));
141+ /// option.change_to_none();
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