-
Notifications
You must be signed in to change notification settings - Fork 177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add note about PhantomData and dropck #432
Conversation
src/libs/maintaining-std.md
Outdated
@@ -189,6 +189,23 @@ Changes to collection internals may affect the order their items are dropped in. | |||
|
|||
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. | |||
|
|||
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: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When reading this paragraph, I wouldn't know what "pretends to store a value that may dangle" means -- specifically the "may dangle" part.
The key point here is that if dropping Type<T>
means that a T
could be dropped, then dropck needs to know this. If the drop occurs through the normal auto-generated drop glue, no action is required as dropck know what that one does. But if the drop occurs through a manual drop
impl, then there needs to be a PhantomData<T>
.
Thanks for the review @RalfJung! That first cut was clearly sketchy and deserved more consideration 🙂 How does this look now? I've linked to the appropriate RFC and I've tried to suggest that our original implementation of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah nice, an example makes it a lot clearer.
Few comments:
I've tried to suggest that our original implementation of
OptionCell<T>
without aPhantomData<T>
field was problematic even before we added#[may_dangle]
. Would you agree?
Hm, not sure. Without #[may_dangle]
, dropck assumes we're going to access some potential T
regardless, so that's safe. Although it might be good to add it just in case a #[may_dangle]
is added later, I think it's better to just say that only adding #[may_dangle]
requires thinking about dropck and related PhantomData
.
src/libs/maintaining-std.md
Outdated
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. | ||
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. | ||
|
||
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>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
Type<T>
's ownership ofT
is expressed indirectly through pointers, such as*mut T
orMaybeUninit<T>
This now suggests that MaybeUninit<T>
owns a T through pointers, instead of directly.
Might be good to mention ManuallyDrop<T>
as well. That one's more closely related to the problem, as it does exactly the one thing that makes this problem a problem.
Co-authored-by: Mara Bos <m-ou.se@m-ou.se>
Co-authored-by: Mara Bos <m-ou.se@m-ou.se>
Yes, I was about to raise a similar concern. dropck by default has to assume that a manual |
src/libs/maintaining-std.md
Outdated
impl<T> Drop for OptionCell<T> { | ||
fn drop(&mut self) { | ||
// Safety: The cell is being dropped, so it can't be accessed again. | ||
unsafe { self.take_inner() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to at least state the type signature for take_inner
. I assume it returns Option<T>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or just write out the code:
if self.is_init {
let _ = unsafe { self.value.read() };
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd find drop(unsafe { self.value.read() })
clearer, after all the point is that this drops the value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the most clear explanation of the problem that I have seen so far. :)
We should reference these docs from rust-lang/rust#34761 once the PR lands. |
Co-authored-by: Ralf Jung <post@ralfj.de>
Based on a soundness issue with
SyncOnceCell
introduced when we added a#[may_dangle]
attribute without also informing dropck that we logically own the value: rust-lang/rust#76367cc @matklad @m-ou-se
r? @RalfJung