Skip to content
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

Tracking issue for RFC 2514, "Union initialization and Drop" #55149

Closed
3 of 7 tasks
Centril opened this issue Oct 17, 2018 · 34 comments · Fixed by #97995
Closed
3 of 7 tasks

Tracking issue for RFC 2514, "Union initialization and Drop" #55149

Centril opened this issue Oct 17, 2018 · 34 comments · Fixed by #97995
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. F-untagged_unions `#![feature(untagged_unions)]` finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Centril
Copy link
Contributor

Centril commented Oct 17, 2018

This is a tracking issue for the RFC "Union initialization and Drop" (rust-lang/rfcs#2514).

Successor of #32836.

Steps:

Unresolved questions:

  • There should be more tests in particular for all move-related behaviors (1, 2, 3, 4). Done in unions: test move behavior of non-Copy fields #75559.

  • Should we try to avoid the DerefMut-related pitfall? And if yes, should we maybe try harder, e.g. lint against using * below a union type when describing a place? That would make people write let v = &mut u.f; *v = Vec::new();. It is not clear that this helps in terms of pointing out that an automatic drop may be happening. (Implementation at do not apply DerefMut on union field #75584.)

  • We could allow moving out of a union field even if the union implements Drop. That would have the effect of making the union considered uninitialized, i.e., it would not be dropped implicitly when it goes out of scope. However, it might be useful to not let people do this accidentally. The same effect can always be achieved by having a dropless union wrapped in a newtype struct with the desired Drop.

  • Should we allow impl Copy for Union even when the union has non-Copy fields? (Proposed here.)

Implementation history

@Centril Centril added B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. T-lang Relevant to the language team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Oct 17, 2018
@RalfJung

This comment has been minimized.

@SimonSapin
Copy link
Contributor

Is there anything else tracked in #32836 that is not covered here? Does implementing this RFC mean fully stabilizing the untagged_unions feature?

@Centril
Copy link
Contributor Author

Centril commented Oct 17, 2018

@SimonSapin I just make the issues, so I'll leave the question up to @RalfJung :)

@RalfJung
Copy link
Member

RalfJung commented Oct 17, 2018

Stabilization is separate, right? It has its own checkmark above. :) Implementing the RFC means restricting unions with non-Copy types to the point where I think they can be stabilized, yes.

I am not fully aware of everything that exists behind the untagged_union feature gate though... if e.g. there is such a thing as union patterns, they are not affected by this directly.

Quoting from the other tracking issue:

When moving out of one field of a union, are the others considered invalidated?

This is answered by this RFC.

Under what conditions can you implement Copy for a union? For example, what if some variants are of non-Copy type? All variants?

The RFC doesn't say anything about that, but I think indeed the answer should be "all variants".

What interaction is there between unions and enum layout optimizations?

This is topic of a future unsafe code guidelines discussion, and unrelated to this RFC.

@Aaron1011

This comment has been minimized.

@Gankra

This comment has been minimized.

@Centril

This comment has been minimized.

@eddyb
Copy link
Member

eddyb commented Nov 3, 2018

This is the part that needs to be changed:

let param_env = self.tcx.param_env(def_id);
if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
emit_feature_err(&self.tcx.sess.parse_sess,
"untagged_unions", item.span, GateIssue::Language,
"unions with non-`Copy` fields are unstable");
}

It should be possible to change it to ty.needs_drop(self.tcx, param_env).

(note that this will remain valid only as long as nobody changes the implementation of needs_drop to return false for unions without checking! but if we add tests we should be fine)

Turns out... I was wrong from the start, needs_drop always returns false for unions.
Which means we need this:

adt_def.non_enum_variant().fields.iter().any(|field| {
    self.tcx.type_of(field.did).needs_drop(self.tcx, param_env)
})

Also, this shouldn't be nested in the else for the has_dtor check.

@RalfJung
Copy link
Member

RalfJung commented Nov 3, 2018

Behavior if the check failed should then also change from "require feature flag" to "hard error".

@RalfJung

This comment has been minimized.

Centril added a commit to Centril/rust that referenced this issue Oct 21, 2019
… r=RalfJung

Change untagged_unions to not allow union fields with drop

This is a rebase of rust-lang#56440, massaged to solve merge conflicts and make the test suite pass.

Change untagged_unions to not allow union fields with drop

Union fields may now never have a type with attached destructor. This for example allows unions to use arbitrary field types only by wrapping them in `ManuallyDrop` (or similar).

The stable rule remains, that union fields must be `Copy`. We use the new rule for the `untagged_union` feature.

Tracking issue: rust-lang#55149
Centril added a commit to Centril/rust that referenced this issue Oct 21, 2019
… r=RalfJung

Change untagged_unions to not allow union fields with drop

This is a rebase of rust-lang#56440, massaged to solve merge conflicts and make the test suite pass.

Change untagged_unions to not allow union fields with drop

Union fields may now never have a type with attached destructor. This for example allows unions to use arbitrary field types only by wrapping them in `ManuallyDrop` (or similar).

The stable rule remains, that union fields must be `Copy`. We use the new rule for the `untagged_union` feature.

Tracking issue: rust-lang#55149
@SimonSapin
Copy link
Contributor

#62330 has landed. Are there remaining changes specified in the RFC that are not implemented yet?

@Centril Centril added B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Oct 23, 2019
@haaami01

This comment has been minimized.

@RalfJung

This comment has been minimized.

@joshtriplett
Copy link
Member

It sounds like this has been fully implemented, and the current state of unions is roughly where we want them to be. ManuallyDrop is available, and unions (in stable) don't allow Drop/non-Copy fields.

We'd like to close the remainder of this, and just not allow non-Copy union fields in general, changing that from a feature gate to an error.

@rfcbot close

@rfcbot
Copy link

rfcbot commented Jun 8, 2022

Team member @joshtriplett has proposed to close this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Jun 8, 2022
@rfcbot
Copy link

rfcbot commented Jun 8, 2022

🔔 This is now entering its final comment period, as per the review above. 🔔

@RalfJung
Copy link
Member

FWIW, when the untagged_unions feature is removed, the AssignToDroppingUnionField unsafety kind can also be removed -- it is impossible to trigger without that feature.

@RalfJung
Copy link
Member

In #97995 I am suggesting to allow a few more types for union fields on stable (specifically: mutable references), before we entirely remove the untagged_unions feature.

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Jun 18, 2022
@rfcbot
Copy link

rfcbot commented Jun 18, 2022

The final comment period, with a disposition to close, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Jul 12, 2022
…Simulacrum

allow unions with mutable references and tuples of allowed types

We currently allow shared references in unions, but not mutable references. That seems somewhat inconsistent. So let's allow all references, and while we are at it, let's make sure the set of allowed types is closed under tuples.

This will need T-lang FCP (at least).

Then remove the `tagged_unions` feature, since we do not plan to stabilize any more of it.
Closes rust-lang#55149
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Jul 12, 2022
…Simulacrum

allow unions with mutable references and tuples of allowed types

We currently allow shared references in unions, but not mutable references. That seems somewhat inconsistent. So let's allow all references, and while we are at it, let's make sure the set of allowed types is closed under tuples.

This will need T-lang FCP (at least).

Then remove the `tagged_unions` feature, since we do not plan to stabilize any more of it.
Closes rust-lang#55149
@bors bors closed this as completed in cbb07c2 Jul 14, 2022
@raphaelcohn
Copy link

@joshtriplett @RalfJung I think removing this has exposed an overlooked use case that should work, but now doesn't.

struct StackWithoutLength<T, const N: usize>(ManuallyDrop<MaybeUninit<[T; N]>>);

union StackWithoutLengthOrHeap<T, const N: usize>
{
	stack_without_length: StackWithoutLength<T, N>,

         copyable: u32
}

This now fails to compile with error[E0740]: unions cannot contain fields that may need dropping (details below), when it seems like it should; trivial analysis suggests that StackWithoutLength` is a new type that can only be manually dropped...

error[E0740]: unions cannot contain fields that may need dropping
 --> swiss-army-knife/src/const_small_vec/StackWithoutLengthOrHeap.rs:7:2
  |
7 |     stack_without_length: StackWithoutLength<T, N>,
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
  |
7 |     stack_without_length: std::mem::ManuallyDrop<StackWithoutLength<T, N>>,
  |                           +++++++++++++++++++++++                        +

@RalfJung
Copy link
Member

RalfJung commented Aug 9, 2022

Never inspecting the fields of a struct for this check was a deliberate design decision, since if that struct was in a different crate, it might start needing drop in future versions of the crate.

In this case, it seems like the struct and union are in the same crate? Possibly an exception could be made for that case, though it would be an extension of the RFC. Please open a feature request issue.

@raphaelcohn
Copy link

@RalfJung thanks for the quick reply. The struct and union are in the same crate and both are private too it, as well.

If versions are correctly used, then a future version of the struct should then cause failure.

I won't be opening a feature request.

@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Sep 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. F-untagged_unions `#![feature(untagged_unions)]` finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.