Rollup merge of #130279 - theemathas:manually-drop-docs, r=thomcc,tra… · qinheping/verify-rust-std@805d196 (original) (raw)
1
1
`use crate::ops::{Deref, DerefMut, DerefPure};
`
2
2
`use crate::ptr;
`
3
3
``
4
``
`` -
/// A wrapper to inhibit the compiler from automatically calling T
’s destructor.
``
5
``
`-
/// This wrapper is 0-cost.
`
``
4
`` +
/// A wrapper to inhibit the compiler from automatically calling T
’s
``
``
5
`+
/// destructor. This wrapper is 0-cost.
`
6
6
`///
`
7
7
`` /// ManuallyDrop<T>
is guaranteed to have the same layout and bit validity as
``
8
``
`` -
/// T
, and is subject to the same layout optimizations as T
. As a consequence,
``
9
``
`-
/// it has no effect on the assumptions that the compiler makes about its
`
10
``
`` -
/// contents. For example, initializing a ManuallyDrop<&mut T>
with [mem::zeroed
]
``
11
``
`-
/// is undefined behavior. If you need to handle uninitialized data, use
`
12
``
`` -
/// [MaybeUninit<T>
] instead.
``
``
8
`` +
/// T
, and is subject to the same layout optimizations as T
. As a
``
``
9
`+
/// consequence, it has no effect on the assumptions that the compiler makes
`
``
10
`` +
/// about its contents. For example, initializing a ManuallyDrop<&mut T>
with
``
``
11
`` +
/// [mem::zeroed
] is undefined behavior. If you need to handle uninitialized
``
``
12
`` +
/// data, use [MaybeUninit<T>
] instead.
``
13
13
`///
`
14
``
`` -
/// Note that accessing the value inside a ManuallyDrop<T>
is safe.
``
15
``
`` -
/// This means that a ManuallyDrop<T>
whose content has been dropped must not
``
16
``
`-
/// be exposed through a public safe API.
`
17
``
`` -
/// Correspondingly, ManuallyDrop::drop
is unsafe.
``
``
14
`` +
/// Note that accessing the value inside a ManuallyDrop<T>
is safe. This means
``
``
15
`` +
/// that a ManuallyDrop<T>
whose content has been dropped must not be exposed
``
``
16
`` +
/// through a public safe API. Correspondingly, ManuallyDrop::drop
is unsafe.
``
18
17
`///
`
19
``
`` -
/// # ManuallyDrop
and drop order.
``
``
18
`` +
/// # ManuallyDrop
and drop order
``
20
19
`///
`
21
20
`/// Rust has a well-defined [drop order] of values. To make sure that fields or
`
22
21
`/// locals are dropped in a specific order, reorder the declarations such that
`
`@@ -40,9 +39,116 @@ use crate::ptr;
`
40
39
`/// }
`
41
40
```` /// ```
`42`
`41`
`///
`
``
`42`
`` +
/// # Interaction with `Box`
``
``
`43`
`+
///
`
``
`44`
`` +
/// Currently, if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or
``
``
`45`
`` +
/// contains a `Box` inside, then dropping the `T` followed by moving the
``
``
`46`
`` +
/// `ManuallyDrop<T>` is [considered to be undefined
``
``
`47`
`+
/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
`
``
`48`
`+
/// That is, the following code causes undefined behavior:
`
``
`49`
`+
///
`
``
`50`
```` +
/// ```no_run
``
51
`+
/// use std::mem::ManuallyDrop;
`
``
52
`+
///
`
``
53
`+
/// let mut x = ManuallyDrop::new(Box::new(42));
`
``
54
`+
/// unsafe {
`
``
55
`+
/// ManuallyDrop::drop(&mut x);
`
``
56
`+
/// }
`
``
57
`+
/// let y = x; // Undefined behavior!
`
``
58
/// ```
``
59
`+
///
`
``
60
`+
/// This is [likely to change in the
`
``
61
`+
/// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the
`
``
62
`` +
/// meantime, consider using [MaybeUninit
] instead.
``
``
63
`+
///
`
``
64
`` +
/// # Safety hazards when storing ManuallyDrop
in a struct or an enum.
``
``
65
`+
///
`
``
66
`+
/// Special care is needed when all of the conditions below are met:
`
``
67
`` +
/// * A struct or enum contains a ManuallyDrop
.
``
``
68
`` +
/// * The ManuallyDrop
is not inside a union
.
``
``
69
`+
/// * The struct or enum is part of public API, or is stored in a struct or an
`
``
70
`+
/// enum that is part of public API.
`
``
71
`` +
/// * There is code that drops the contents of the ManuallyDrop
field, and
``
``
72
`` +
/// this code is outside the struct or enum's Drop
implementation.
``
``
73
`+
///
`
``
74
`+
/// In particular, the following hazards may occur:
`
``
75
`+
///
`
``
76
`+
/// #### Storing generic types
`
``
77
`+
///
`
``
78
`` +
/// If the ManuallyDrop
contains a client-supplied generic type, the client
``
``
79
`` +
/// might provide a Box
as that type. This would cause undefined behavior when
``
``
80
`+
/// the struct or enum is later moved, as mentioned in the previous section. For
`
``
81
`+
/// example, the following code causes undefined behavior:
`
``
82
`+
///
`
``
83
/// ```no_run
``
84
`+
/// use std::mem::ManuallyDrop;
`
``
85
`+
///
`
``
86
`+
/// pub struct BadOption {
`
``
87
`` +
/// // Invariant: Has been dropped iff is_some
is false.
``
``
88
`+
/// value: ManuallyDrop,
`
``
89
`+
/// is_some: bool,
`
``
90
`+
/// }
`
``
91
`+
/// impl BadOption {
`
``
92
`+
/// pub fn new(value: T) -> Self {
`
``
93
`+
/// Self { value: ManuallyDrop::new(value), is_some: true }
`
``
94
`+
/// }
`
``
95
`+
/// pub fn change_to_none(&mut self) {
`
``
96
`+
/// if self.is_some {
`
``
97
`+
/// self.is_some = false;
`
``
98
`+
/// unsafe {
`
``
99
`` +
/// // SAFETY: value
hasn't been dropped yet, as per the invariant
``
``
100
`+
/// // (This is actually unsound!)
`
``
101
`+
/// ManuallyDrop::drop(&mut self.value);
`
``
102
`+
/// }
`
``
103
`+
/// }
`
``
104
`+
/// }
`
``
105
`+
/// }
`
``
106
`+
///
`
``
107
`+
/// // In another crate:
`
``
108
`+
///
`
``
109
`+
/// let mut option = BadOption::new(Box::new(42));
`
``
110
`+
/// option.change_to_none();
`
``
111
`+
/// let option2 = option; // Undefined behavior!
`
``
112
/// ```
``
113
`+
///
`
``
114
`+
/// #### Deriving traits
`
``
115
`+
///
`
``
116
`` +
/// Deriving Debug
, Clone
, PartialEq
, PartialOrd
, Ord
, or Hash
on
``
``
117
`+
/// the struct or enum could be unsound, since the derived implementations of
`
``
118
`` +
/// these traits would access the ManuallyDrop
field. For example, the
``
``
119
`+
/// following code causes undefined behavior:
`
``
120
`+
///
`
``
121
/// ```no_run
``
122
`+
/// use std::mem::ManuallyDrop;
`
``
123
`+
///
`
``
124
`` +
/// // This derive is unsound in combination with the ManuallyDrop::drop
call.
``
``
125
`+
/// #[derive(Debug)]
`
``
126
`+
/// pub struct Foo {
`
``
127
`+
/// value: ManuallyDrop,
`
``
128
`+
/// }
`
``
129
`+
/// impl Foo {
`
``
130
`+
/// pub fn new() -> Self {
`
``
131
`+
/// let mut temp = Self {
`
``
132
`+
/// value: ManuallyDrop::new(String::from("Unsafe rust is hard."))
`
``
133
`+
/// };
`
``
134
`+
/// unsafe {
`
``
135
`` +
/// // SAFETY: value
hasn't been dropped yet.
``
``
136
`+
/// ManuallyDrop::drop(&mut temp.value);
`
``
137
`+
/// }
`
``
138
`+
/// temp
`
``
139
`+
/// }
`
``
140
`+
/// }
`
``
141
`+
///
`
``
142
`+
/// // In another crate:
`
``
143
`+
///
`
``
144
`+
/// let foo = Foo::new();
`
``
145
`+
/// println!("{:?}", foo); // Undefined behavior!
`
``
146
/// ```
``
147
`+
///
`
43
148
`/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
`
44
149
`` /// [mem::zeroed
]: crate::mem::zeroed
``
45
150
`` /// [MaybeUninit<T>
]: crate::mem::MaybeUninit
``
``
151
`` +
/// [MaybeUninit
]: crate::mem::MaybeUninit
``
46
152
`#[stable(feature = "manually_drop", since = "1.20.0")]
`
47
153
`#[lang = "manually_drop"]
`
48
154
`#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
`