-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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 empty dropped variant to ManuallyDrop #49056
Conversation
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
Do we have to "assign" to .dropped in the drop method? Not sure what the semantics of unions are exactly. |
@sfackler I suppose you could |
cc #47650 @mikeyhew @nikomatsakis. This PR is going to invalidate the entire presumption of #47650, that |
An alternate interpretation for the |
But how could you construct an |
@sfackler If we went that route, we'd make it legal to construct any union by specifying either 0 or 1 field (rather than exactly one, as it is today). |
Ah sure |
@eddyb drew a distinction between |
@rkruppe I'm having a hard time understanding that distinction, since |
@cramertj See the discussion preceding the comment I linked. Kind of hard to tell where it starts but this #47650 (comment) might be a reasonably close starting point. But basically IIUC the argument goes that "initializing and then dropping" leaves some values intact and is therefore different from never having initialized at all. |
Yeah, I read that, and I'm unsure whether I agree or not :) While it is definitely the case that some types have a valid repr even after being dropped (like primitives or As I type this, I'm coming around to the idea more and more, however I'm having trouble formalizing it: the property is something like "a union contains data that is a valid bit-based representation of one of its variants, but does not necessarily enforce the type's usual invariants". For example, Because the same rules apply to But I also might be massively overcomplicating this-- perhaps this rule can be phrased in a way that has a much smaller scope than I'm imagining. |
After thinking about this more, I've convinced myself that any memory model we adopt would require that a value of type T which has had |
Is this because I'm not really convinced by this line of argument, but it also doesn't seem obvious that the "usual rules" must apply to the And besides, your formulation doesn't really say anything about the validity of the value after drop glue has run on it. |
A bit off-topic, but one of the main reasons I want |
@rkruppe yeah, that's one of the main reasons. The other is that it allows me to make sense of the way unions are being used in @eddyb's preferred model-- that there's a differentiation between uninit and dropped T, whereas I had previously been considering both as just "not a |
I'm going to reopen this because there's a serious question here that has been left unanswered, and I think we should make some sort of a decision here before closing this (at least without a followup RFC or tracking issue). There are a few options:
|
With "enum interpretation" of unions |
@petrochenkov except that dropping a single-field union does not drop the field it contains, whereas dropping a single-field struct does. I think that's the only difference though, right? |
@cramertj thanks for posting this, I think it's important that we get a formal definition here before stabilizing unions with drop fields.
My understanding when opening #47650 was that one of these two statements was true. Is there a practical difference between them?
I think this is a typo, do you mean "uninitialized"? |
It's primarily an issue of how to define things, specifically what it means for a value to have type
Yup, fixed. |
My personal expectation so far was that adding an empty variant to a union is pretty much a NOP. I imagined unions would be "barriers" to type validity; the compiler would never assume anything "for free" about data below a union (just like it never assumes anything "for free" for data below an In particular, I expected that a union with a The main reason for this is simplicity and consistency. If we decide that the contents of unions can matter, there are just so many questions to answer. Are single-field unions special? Or is a union with three fields, all of which are I have to admit I don't fully understand @eddyb's reasoning in the other thread, in particular the part at #47650 (comment) is entirely lost on me. If someone could explain why making unions "ignore" the valid bit-patterns of their inner types is a bad idea, that'd be appreciated. :) Is it "just" the layout-based optimizations?
New typestates seem to crop up everywhere recently. ;)
They would not necessarily invalid, it all depends on which requirements we make for that "typestate". I see variant 2 as a special case of variant 1. Also, just reading uninitialized data is fine, so I can't actually think of any reasonable optimization that could be invalidated. Could you give an example? At some point on IRC I've been talking with @eddyb about the contract for Either way, I imagine even an unsafe type has very little freedom in picking its "dropped" invariant. In fact, I think it is always fully determined structurally; is there any utility in types being able to still have private invariants in this state? Also, may I add "variant 4": The value inside the union can be anything. That's what I described above. The "completely dropped" typestate would then always have the trivial invariant that does not assume anything. |
To clarify, I think your interpretation is this option:
in my comment above, right? |
Ah, yes. I read that but then forgot about it when replying... sorry. Yes, that is "variant 4". |
Ping from triage! What's the status of this PR? |
This is now on the unsafe code guidelines agenda: https://internals.rust-lang.org/t/proposal-reboot-the-unsafe-code-guidelines-team-as-a-working-group/7307 |
Marking this as blocked on some consensus from the unsafe guidelines WG. |
Closing until some consensus is reached by the unsafe guidelines WG. |
For future reference, I think I now actually understood #49056 (comment): (Quoting from #51361 (comment))
As @eddyb remarked, |
I think we should not do this, see https://internals.rust-lang.org/t/pre-rfc-unions-drop-types-and-manuallydrop/8025 for further details. This actually side-steps having unsafe code guidelines involved by making |
|
Change
ManuallyDrop
's internal (unstable) representation to match the design ofMaybeUninit
in rust-lang/rfcs#1892. This indicates that the union has more than one possible representation variant. After the inner type has been dropped, it is no longer a validT
, and so the union should be considered to contain only()
.cc @canndrew @RalfJung