Repository navigation
PhantomData<T> no longer dropck? #70841
Description
Activity
It, however, compiles and runs on 1.42 and 1.31.
It fails to compile with the 2015 edition on 1.31, so it's probably caused by NLL.
I suspect the issue is something like:
PhantomDatanever "needs drop", so your struct also doesn't, so noDropterminator is created that could access the borrowed value.- addedA-NLLArea: Non-lexical lifetimes (NLL)Area: Non-lexical lifetimes (NLL)I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
on Apr 6, 2020 Adding an unrelated field that has a destructor makes the error appear again
Regression from 1.36: https://rust.godbolt.org/z/hnEi6A
Assigning
P-highto this bug and leaving the nomination, this could have beenP-criticaltoo. This was discussed as part of our pre-triage meeting in Zulip.21 remaining items
@danielhenrymantilla Yeah, something like that is what I was imagining... though your code still has
#[may_dangle] dropon the same typeRemoteDropthat also has thePhantomData. I think I was imagining putting the function pointer anddropimpl down into another type, so that#[may_dangle]andPhantomDataare on two different types.I am not sure why
RawOptionwould be needed?@RalfJung I'm still confused about:
This is unsound because of the lack of
PhantomData, no matter whether the drop impl ismay_dangleor not.From my understanding of dropck, considering
MyBox<T>impl no#[may_dangle]Drop:If it construct
-
without
PhantomData<T>, the dropck would be:dropck(MyBox<T>, 'scope) := T: 'scope(strictly) -
with
PhantomData<T>:dropck(MyBox<T>, 'scope) := T: 'scope & dropck(T, 'scope)wheredropck(PhantomData<T>, 'scope) := dropck(T, 'scope)
If you want to construct a ub from the former, it is equivalent to finding a
Tthat satisfiesT: 'scopebut notdropck(T, 'scope), and causes ub when it destructs.But I tried to construct such a
Tand failed. I can't even find a counterexample forT:' scope - > dropck(T, 'scope).And I'm not sure how this violates dropck:
I still have an idea for a counterexample but it's getting tricky: a type not having
Tin its parameters at all (some kind oft type erasure going on) would have to still drop aT. TheTwould be remembered by an outer wrapper type that however does not have a destructor.-
- Wow this is an ancient thread, and I lost all context. Could you link to the context where I said that? Also I recently opened #103413, does that help?
Re-reading the thread above, it seems to be about the same fundamental question as #102810. Curious.
My PR fixes the documentation paragraph that @pnkfelix quoted above
Adding a field of type PhantomData indicates that your type owns data of type T. This in turn implies that when your type is dropped, it may drop one or more instances of the type T. This has bearing on the Rust compiler's drop check analysis.
They also wrote
I do worry a little bit about the user's mental model for this case, however. The claim "PhantomData is just like a T" doesn't quite hold up. (not that it ever did ...)
which is still true and would require pretty fundamental changes to NLL at this point.
I know
PhatomDataonly works on needs_drop types dropping.I'm just curious how the following code causes ub, and how it violates dropck rules:
For example:
struct MyBox<T>(NonNull<T>); // Mirror `Box` API, including `Drop`.
This is unsound because of the lack of PhantomData, no matter whether the drop impl is may_dangle or not.
Oh, I will note that :D.
PhantomData is never needed for Drop unless you use may_dangle
But as the example in #103413 (comment),
PhantomDatastill works for "normal" dropping.(without#[may_dangle])Yeah I read that thread after this one.^^ The summary is "it's complicated, hopefully we'll figure it out in #103413". Let's not re-post everything in two spots. :)
Reacted by Danube- added a commit that references this issue
on May 13, 2023 - added a commit that references this issue
on Jul 18, 2023 - added a commit that references this issue
on Apr 20, 2024 - added a commit that references this issue
on Apr 27, 2024 - added a commit that references this issue
on Feb 3, 2026
Consider this code:
Playground
I believe it should not compile (by failing dropcheck). It, however, compiles and runs on 1.42 and 1.31. On 1.24 it indeed fails as I expect.
The equivalent code, where
PhantomData<T>is replaced withTrightfully fails to compiles: Playground. So, dropchk somehow observes the difference betweenTandPhantomData<T>?Either I misunderstand how
PhantomData<T>is supposed to work, or this is a stable-to-stable regression and a soundless hole.