diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index ca008a82ee6f0..4d9828b91061a 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -43,24 +43,6 @@ use crate::ptr; /// } /// ``` /// -/// # Interaction with `Box` -/// -/// Currently, if you have a `ManuallyDrop`, where the type `T` is a `Box` or -/// contains a `Box` inside, then dropping the `T` followed by moving the -/// `ManuallyDrop` is [considered to be undefined -/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245). -/// That is, the following code causes undefined behavior: -/// -/// ```no_run -/// use std::mem::ManuallyDrop; -/// -/// let mut x = ManuallyDrop::new(Box::new(42)); -/// unsafe { -/// ManuallyDrop::drop(&mut x); -/// } -/// let y = x; // Undefined behavior! -/// ``` -/// /// This is [likely to change in the /// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the /// meantime, consider using [`MaybeUninit`] instead. @@ -75,14 +57,59 @@ use crate::ptr; /// * There is code that drops the contents of the `ManuallyDrop` field, and /// this code is outside the struct or enum's `Drop` implementation. /// -/// In particular, the following hazards may occur: +/// In particular, deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, +/// or `Hash` on the struct or enum could be unsound, since the derived +/// implementations of these traits would access the `ManuallyDrop` field. For +/// example, the following code causes undefined behavior: /// -/// #### Storing generic types +/// ```no_run +/// use std::mem::ManuallyDrop; /// -/// If the `ManuallyDrop` contains a client-supplied generic type, the client -/// might provide a `Box` as that type. This would cause undefined behavior when -/// the struct or enum is later moved, as mentioned in the previous section. For -/// example, the following code causes undefined behavior: +/// // This derive is unsound in combination with the `ManuallyDrop::drop` call. +/// #[derive(Debug)] +/// pub struct Foo { +/// value: ManuallyDrop, +/// } +/// impl Foo { +/// pub fn new() -> Self { +/// let mut temp = Self { +/// value: ManuallyDrop::new(String::from("Unsafe rust is hard.")) +/// }; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet. +/// ManuallyDrop::drop(&mut temp.value); +/// } +/// temp +/// } +/// } +/// +/// // In another crate: +/// +/// let foo = Foo::new(); +/// println!("{:?}", foo); // Undefined behavior! +/// ``` +/// +/// # Pre-`1.96` Interaction with `Box` +/// +/// Before Rust `1.96.0`, if you had a `ManuallyDrop`, where the type `T` +/// was a `Box` or contained a `Box` inside, then dropping the `T` followed by +/// moving the `ManuallyDrop` was [considered to be undefined +/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245). +/// That is, the following code caused undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// let mut x = ManuallyDrop::new(Box::new(42)); +/// unsafe { +/// ManuallyDrop::drop(&mut x); +/// } +/// let y = x; // Undefined behavior! (pre 1.96.0) +/// ``` +/// +/// Note that this could also have happen with a generic type where the user of +/// the library providing it could substitute the generic for a `Box<_>` and +/// then move the library type: /// /// ```no_run /// use std::mem::ManuallyDrop; @@ -101,7 +128,7 @@ use crate::ptr; /// self.is_some = false; /// unsafe { /// // SAFETY: `value` hasn't been dropped yet, as per the invariant -/// // (This is actually unsound!) +/// // (This is actually unsound pre rust 1.96.0!) /// ManuallyDrop::drop(&mut self.value); /// } /// } @@ -112,41 +139,7 @@ use crate::ptr; /// /// let mut option = BadOption::new(Box::new(42)); /// option.change_to_none(); -/// let option2 = option; // Undefined behavior! -/// ``` -/// -/// #### Deriving traits -/// -/// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on -/// the struct or enum could be unsound, since the derived implementations of -/// these traits would access the `ManuallyDrop` field. For example, the -/// following code causes undefined behavior: -/// -/// ```no_run -/// use std::mem::ManuallyDrop; -/// -/// // This derive is unsound in combination with the `ManuallyDrop::drop` call. -/// #[derive(Debug)] -/// pub struct Foo { -/// value: ManuallyDrop, -/// } -/// impl Foo { -/// pub fn new() -> Self { -/// let mut temp = Self { -/// value: ManuallyDrop::new(String::from("Unsafe rust is hard.")) -/// }; -/// unsafe { -/// // SAFETY: `value` hasn't been dropped yet. -/// ManuallyDrop::drop(&mut temp.value); -/// } -/// temp -/// } -/// } -/// -/// // In another crate: -/// -/// let foo = Foo::new(); -/// println!("{:?}", foo); // Undefined behavior! +/// let option2 = option; // Undefined behavior! (pre 1.96) /// ``` /// /// [drop order]: https://doc.rust-lang.org/reference/destructors.html