Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 53 additions & 60 deletions library/core/src/mem/manually_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,6 @@ use crate::ptr;
/// }
/// ```
///
/// # Interaction with `Box`
///
/// Currently, if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or
/// contains a `Box` inside, then dropping the `T` followed by moving the
/// `ManuallyDrop<T>` 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.
Expand All @@ -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<String>,
/// }
/// 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<T>`, where the type `T`
/// was a `Box` or contained a `Box` inside, then dropping the `T` followed by
/// moving the `ManuallyDrop<T>` 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;
Expand All @@ -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);
/// }
/// }
Expand All @@ -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<String>,
/// }
/// 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
Expand Down
Loading