Skip to content

Commit 9c32e7a

Browse files
authored
Rollup merge of rust-lang#71625 - Diggsey:improve-manually-drop-docs, r=RalfJung
Improve the documentation for ManuallyDrop to resolve conflicting usage of terminology cc @RalfJung Follow-up from rust-lang/unsafe-code-guidelines#233
2 parents 584252b + 7433c4d commit 9c32e7a

File tree

2 files changed

+36
-11
lines changed

2 files changed

+36
-11
lines changed

src/libcore/mem/manually_drop.rs

+29-10
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ use crate::ptr;
77
///
88
/// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
99
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
10-
/// about all values being initialized at their type. In particular, initializing
11-
/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
10+
/// about its contents. For example, initializing a `ManuallyDrop<&mut T>`
11+
/// with [`mem::zeroed`] is undefined behavior.
1212
/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
1313
///
1414
/// # Examples
1515
///
16-
/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
17-
/// the type:
16+
/// This wrapper can be used to enforce a particular drop order on fields, regardless
17+
/// of how they are defined in the struct:
1818
///
1919
/// ```rust
2020
/// use std::mem::ManuallyDrop;
@@ -43,8 +43,18 @@ use crate::ptr;
4343
/// }
4444
/// ```
4545
///
46+
/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
47+
/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
48+
/// would also be leaked.
49+
///
50+
/// In contrast, the automatically-generated compiler drop implementation would have ensured
51+
/// that all fields are dropped even in the presence of panics. This is especially important when
52+
/// working with [pinned] data, where reusing the memory without calling the destructor could lead
53+
/// to Undefined Behaviour.
54+
///
4655
/// [`mem::zeroed`]: fn.zeroed.html
4756
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
57+
/// [pinned]: ../pin/index.html
4858
#[stable(feature = "manually_drop", since = "1.20.0")]
4959
#[lang = "manually_drop"]
5060
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -113,19 +123,28 @@ impl<T> ManuallyDrop<T> {
113123
}
114124

115125
impl<T: ?Sized> ManuallyDrop<T> {
116-
/// Manually drops the contained value.
126+
/// Manually drops the contained value. This is exactly equivalent to calling
127+
/// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless
128+
/// the contained value is a packed struct, the destructor will be called in-place
129+
/// without moving the value, and thus can be used to safely drop [pinned] data.
117130
///
118131
/// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
119132
///
120133
/// # Safety
121134
///
122-
/// This function runs the destructor of the contained value and thus the wrapped value
123-
/// now represents uninitialized data. It is up to the user of this method to ensure the
124-
/// uninitialized data is not actually used.
125-
/// In particular, this function can only be called at most once
126-
/// for a given instance of `ManuallyDrop<T>`.
135+
/// This function runs the destructor of the contained value. Other than changes made by
136+
/// the destructor itself, the memory is left unchanged, and so as far as the compiler is
137+
/// concerned still holds a bit-pattern which is valid for the type `T`.
138+
///
139+
/// However, this "zombie" value should not be exposed to safe code, and this function
140+
/// should not be called more than once. To use a value after it's been dropped, or drop
141+
/// a value multiple times, can cause Undefined Behavior (depending on what `drop` does).
142+
/// This is normally prevented by the type system, but users of `ManuallyDrop` must
143+
/// uphold those guarantees without assistance from the compiler.
127144
///
128145
/// [`ManuallyDrop::into_inner`]: #method.into_inner
146+
/// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
147+
/// [pinned]: ../pin/index.html
129148
#[stable(feature = "manually_drop", since = "1.20.0")]
130149
#[inline]
131150
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {

src/libcore/ptr/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,17 @@ mod mut_ptr;
110110
/// as the compiler doesn't need to prove that it's sound to elide the
111111
/// copy.
112112
///
113+
/// * It can be used to drop [pinned] data when `T` is not `repr(packed)`
114+
/// (pinned data must not be moved before it is dropped).
115+
///
113116
/// Unaligned values cannot be dropped in place, they must be copied to an aligned
114-
/// location first using [`ptr::read_unaligned`].
117+
/// location first using [`ptr::read_unaligned`]. For packed structs, this move is
118+
/// done automatically by the compiler. This means the fields of packed structs
119+
/// are not dropped in-place.
115120
///
116121
/// [`ptr::read`]: ../ptr/fn.read.html
117122
/// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html
123+
/// [pinned]: ../pin/index.html
118124
///
119125
/// # Safety
120126
///

0 commit comments

Comments
 (0)