]> git.lizzy.rs Git - rust.git/commitdiff
Improve the documentation for ManuallyDrop to resolve conflicting usage of terminology.
authorDiggory Blake <diggsey@googlemail.com>
Mon, 27 Apr 2020 21:50:55 +0000 (22:50 +0100)
committerDiggory Blake <diggsey@googlemail.com>
Fri, 15 May 2020 18:53:05 +0000 (19:53 +0100)
src/libcore/mem/manually_drop.rs
src/libcore/ptr/mod.rs

index 9e5c2b10d0d9ece6d2938be31a0cb278a1dfd4ef..17863dd38afeeceb086d859d3a7896c829d62b17 100644 (file)
@@ -7,14 +7,14 @@
 ///
 /// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
 /// As a consequence, it has *no effect* on the assumptions that the compiler makes
-/// about all values being initialized at their type.  In particular, initializing
-/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
+/// about its contents. For example, initializing a `ManuallyDrop<&mut T>`
+/// with [`mem::zeroed`] is undefined behavior.
 /// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
 ///
 /// # Examples
 ///
-/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
-/// the type:
+/// This wrapper can be used to enforce a particular drop order on fields, regardless
+/// of how they are defined in the struct:
 ///
 /// ```rust
 /// use std::mem::ManuallyDrop;
 /// }
 /// ```
 ///
+/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
+/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
+/// would also be leaked.
+///
+/// In contrast, the automatically-generated compiler drop implementation would have ensured
+/// that all fields are dropped even in the presence of panics. This is especially important when
+/// working with [pinned] data, where reusing the memory without calling the destructor could lead
+/// to Undefined Behaviour.
+///
 /// [`mem::zeroed`]: fn.zeroed.html
 /// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [pinned]: ../pin/index.html
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -113,19 +123,28 @@ pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
 }
 
 impl<T: ?Sized> ManuallyDrop<T> {
-    /// Manually drops the contained value.
+    /// Manually drops the contained value. This is exactly equivalent to calling
+    /// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless
+    /// the contained value is a packed struct, the destructor will be called in-place
+    /// without moving the value, and thus can be used to safely drop [pinned] data.
     ///
     /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
     ///
     /// # Safety
     ///
-    /// This function runs the destructor of the contained value and thus the wrapped value
-    /// now represents uninitialized data. It is up to the user of this method to ensure the
-    /// uninitialized data is not actually used.
-    /// In particular, this function can only be called at most once
-    /// for a given instance of `ManuallyDrop<T>`.
+    /// This function runs the destructor of the contained value. Other than changes made by
+    /// the destructor itself, the memory is left unchanged, and so as far as the compiler is
+    /// concerned still holds a bit-pattern which is valid for the type `T`.
+    ///
+    /// However, this "zombie" value should not be exposed to safe code, and this function
+    /// should not be called more than once. To use a value after it's been dropped, or drop
+    /// a value multiple times, can cause Undefined Behavior (depending on what `drop` does).
+    /// This is normally prevented by the type system, but users of `ManuallyDrop` must
+    /// uphold those guarantees without assistance from the compiler.
     ///
     /// [`ManuallyDrop::into_inner`]: #method.into_inner
+    /// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
+    /// [pinned]: ../pin/index.html
     #[stable(feature = "manually_drop", since = "1.20.0")]
     #[inline]
     pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
index 84f28488c74b678c8e28f5adf179a392478a3076..115194a65a0c2026d751af5736bcfa79671bdc91 100644 (file)
 ///   as the compiler doesn't need to prove that it's sound to elide the
 ///   copy.
 ///
+/// * It can be used to drop [pinned] data when `T` is not `repr(packed)`
+///   (pinned data must not be moved before it is dropped).
+///
 /// Unaligned values cannot be dropped in place, they must be copied to an aligned
-/// location first using [`ptr::read_unaligned`].
+/// location first using [`ptr::read_unaligned`]. For packed structs, this move is
+/// done automatically by the compiler. This means the fields of packed structs
+/// are not dropped in-place.
 ///
 /// [`ptr::read`]: ../ptr/fn.read.html
 /// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html
+/// [pinned]: ../pin/index.html
 ///
 /// # Safety
 ///