Skip to content

Commit 47d2e06

Browse files
authored
Rollup merge of rust-lang#155750 - WaffleLapkin:manually-drop-unbox, r=jhpratt
Document that `ManuallyDrop`'s `Box` interaction has been fixed Both rust-lang#150447 and rust-lang#150446 has been merged in `1.96.0`, fixing the unfortunate `ManuallyDrop<Box<_>>` behavior. cc @RalfJung
2 parents 68ffae4 + 8520b8e commit 47d2e06

1 file changed

Lines changed: 53 additions & 60 deletions

File tree

library/core/src/mem/manually_drop.rs

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)