From a0cf8a6e6443a842ed16158ca60211105cb8ef4c Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 24 Apr 2026 19:55:52 +0200 Subject: [PATCH 1/2] move a section in a doc comment it is not as important anymore (see next comment) --- library/core/src/mem/manually_drop.rs | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index ca008a82ee6f0..2f1f0501e206c 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -43,28 +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. -/// /// # Safety hazards when storing `ManuallyDrop` in a struct or an enum. /// /// Special care is needed when all of the conditions below are met: @@ -149,6 +127,28 @@ use crate::ptr; /// println!("{:?}", foo); // Undefined behavior! /// ``` /// +/// # 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. +/// /// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit From 10eb87718131f008fe58bacb1ce1edbd7147a7a0 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 24 Apr 2026 19:57:56 +0200 Subject: [PATCH 2/2] document that `ManuallyDrop`'s `Box` interaction has been fixed --- library/core/src/mem/manually_drop.rs | 97 ++++++++++++--------------- 1 file changed, 43 insertions(+), 54 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 2f1f0501e206c..b4e274b8e8a4d 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -53,56 +53,14 @@ 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: -/// -/// #### Storing generic types -/// -/// 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 +/// 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: /// /// ```no_run /// use std::mem::ManuallyDrop; /// -/// pub struct BadOption { -/// // Invariant: Has been dropped if `is_some` is false. -/// value: ManuallyDrop, -/// is_some: bool, -/// } -/// impl BadOption { -/// pub fn new(value: T) -> Self { -/// Self { value: ManuallyDrop::new(value), is_some: true } -/// } -/// pub fn change_to_none(&mut self) { -/// if self.is_some { -/// self.is_some = false; -/// unsafe { -/// // SAFETY: `value` hasn't been dropped yet, as per the invariant -/// // (This is actually unsound!) -/// ManuallyDrop::drop(&mut self.value); -/// } -/// } -/// } -/// } -/// -/// // In another crate: -/// -/// 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 { @@ -127,13 +85,13 @@ use crate::ptr; /// println!("{:?}", foo); // Undefined behavior! /// ``` /// -/// # Interaction with `Box` +/// # Pre-`1.96` 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 +/// 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 causes undefined behavior: +/// That is, the following code caused undefined behavior: /// /// ```no_run /// use std::mem::ManuallyDrop; @@ -142,12 +100,43 @@ use crate::ptr; /// unsafe { /// ManuallyDrop::drop(&mut x); /// } -/// let y = x; // Undefined behavior! +/// let y = x; // Undefined behavior! (pre 1.96.0) /// ``` /// -/// 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. +/// 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; +/// +/// pub struct BadOption { +/// // Invariant: Has been dropped if `is_some` is false. +/// value: ManuallyDrop, +/// is_some: bool, +/// } +/// impl BadOption { +/// pub fn new(value: T) -> Self { +/// Self { value: ManuallyDrop::new(value), is_some: true } +/// } +/// pub fn change_to_none(&mut self) { +/// if self.is_some { +/// self.is_some = false; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet, as per the invariant +/// // (This is actually unsound pre rust 1.96.0!) +/// ManuallyDrop::drop(&mut self.value); +/// } +/// } +/// } +/// } +/// +/// // In another crate: +/// +/// let mut option = BadOption::new(Box::new(42)); +/// option.change_to_none(); +/// let option2 = option; // Undefined behavior! (pre 1.96) +/// ``` /// /// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed