You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/libs/maintaining-std.md
+34-7Lines changed: 34 additions & 7 deletions
Original file line number
Diff line number
Diff line change
@@ -187,9 +187,27 @@ Changes to collection internals may affect the order their items are dropped in.
187
187
188
188
### Is there a manual `Drop` implementation?
189
189
190
-
Generic types that manually implement`Drop` should consider whether a `#[may_dangle]` attribute is appropriate. The [Nomicon][dropck] has some details on what `#[may_dangle]` is all about.
190
+
A generic `Type<T>`that manually implements`Drop` should consider whether a `#[may_dangle]` attribute is appropriate on `T`. The [Nomicon][dropck] has some details on what `#[may_dangle]` is all about.
191
191
192
-
If the type pretends to store a value that may dangle, but doesn't do so directly (perhaps through `MaybeUninit<T>` or a raw pointer) then make sure there's an appropriate use of `PhantomData` to support dropck. As a [real-world example][rust/issues/76367], adding a `#[may_dangle]` attribute to an `OptionCell<T>` that internally stores its value as a `MaybeUninit<T>` requires both a `PhantomData` marker and a `#[may_dangle]` attribute:
192
+
If a generic `Type<T>` has a manual drop implementation that may also involve dropping `T` then dropck needs to know about it. If `Type<T>`'s ownership of `T` is expressed indirectly through pointers, such as `*mut T` or `MaybeUninit<T>`, then `Type<T>` also [needs a `PhantomData<T>` field][RFC 0769 PhantomData] to tell dropck that `T` may be dropped. Types in the standard library that use the internal `Unique<T>` pointer type don't need a `PhantomData<T>` marker field. That's taken care of for them by `Unique<T>`.
193
+
194
+
As a real-world example of where this can go wrong, consider an `OptionCell<T>` that looks something like this:
195
+
196
+
```rust
197
+
structOptionCell<T> {
198
+
is_init:bool,
199
+
value:MaybeUninit<T>,
200
+
}
201
+
202
+
implDrop<T> forOptionCell<T> {
203
+
fndrop(&mutself) {
204
+
// Safety: The cell is being dropped, so it can't be accessed again.
205
+
unsafe { self.take_inner() };
206
+
}
207
+
}
208
+
```
209
+
210
+
Adding a `#[may_dangle]` attribute to this `OptionCell<T>` that didn't have a `PhantomData<T>` marker field opened up [a soundness hole][rust/issues/76367] for `T`'s that didn't strictly outlive the `OptionCell<T>`, and so could be accessed after being dropped in their own `Drop` implementations. The `OptionCell<T>` first needed a `PhantomData<T>` field:
193
211
194
212
```diff
195
213
struct OptionCell<T> {
@@ -198,13 +216,21 @@ struct OptionCell<T> {
198
216
+ _marker: PhantomData<T>,
199
217
}
200
218
201
-
- impl Drop<T> OptionCell<T> {
202
-
+ impl Drop<#[may_dangle] T> OptionCell<T> {
203
-
..
204
-
}
219
+
impl Drop<T> for OptionCell<T> {
205
220
```
206
221
207
-
Types in the standard library that use the internal `Unique<T>` don't need a `PhantomData` marker field. That's taken care of for them by `Unique<T>`.
222
+
Then `#[may_dangle]` could be added to the `Drop` implementation:
223
+
224
+
```diff
225
+
struct OptionCell<T> {
226
+
is_init: bool,
227
+
value: MaybeUninit<T>,
228
+
_marker: PhantomData<T>,
229
+
}
230
+
231
+
- impl Drop<T> for OptionCell<T> {
232
+
+ unsafe impl Drop<#[may_dangle] T> for OptionCell<T> {
233
+
```
208
234
209
235
### How could `mem` break assumptions?
210
236
@@ -277,6 +303,7 @@ Where `unsafe` and `const` is involved, e.g., for operations which are "unconst"
0 commit comments