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
+37-1Lines changed: 37 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -187,7 +187,41 @@ 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
+
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 through types that don't drop `T` themselves such as `ManuallyDrop<T>`, `*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
+
impl<T> DropforOptionCell<T> {
203
+
fndrop(&mutself) {
204
+
ifself.is_init {
205
+
// Safety: `value` is guaranteed to be fully initialized when `is_init` is true.
206
+
// Safety: The cell is being dropped, so it can't be accessed again.
207
+
drop(unsafe { self.value.read() });
208
+
}
209
+
}
210
+
}
211
+
```
212
+
213
+
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 correct application of `#[may_dangle]` also required a `PhantomData<T>` field:
214
+
215
+
```diff
216
+
struct OptionCell<T> {
217
+
is_init: bool,
218
+
value: MaybeUninit<T>,
219
+
+ _marker: PhantomData<T>,
220
+
}
221
+
222
+
- impl<T> Drop for OptionCell<T> {
223
+
+ unsafe impl<#[may_dangle] T> Drop for OptionCell<T> {
224
+
```
191
225
192
226
### How could `mem` break assumptions?
193
227
@@ -260,7 +294,9 @@ Where `unsafe` and `const` is involved, e.g., for operations which are "unconst"
0 commit comments