-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Transparent Unions and Enums #2645
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
991ea90
Transparent Unions RFC
mjbshaw e08e4a2
Update text/0000-transparent-unions.md
Centril f7c332e
Update text/0000-transparent-unions.md
Centril cb3f671
Update text/0000-transparent-unions.md
Centril 381fcf6
Update text/0000-transparent-unions.md
Centril eb37cce
Update text/0000-transparent-unions.md
Centril 45be61d
Update text/0000-transparent-unions.md
Centril 582fd15
Update text/0000-transparent-unions.md
Centril d532738
Update text/0000-transparent-unions.md
Centril 4529a95
Update text/0000-transparent-unions.md
Centril bb73505
Update text/0000-transparent-unions.md
Centril f9b9d8e
Update text/0000-transparent-unions.md
Centril 1bce145
Update text/0000-transparent-unions.md
Centril f751ad3
Update text/0000-transparent-unions.md
Centril 7250c02
Update text/0000-transparent-unions.md
Centril bea3b9f
Revise mentions of transparent enums
mjbshaw 038829b
Remove unnecessary "do nothing" alternative
mjbshaw c532471
Clarify generic ZST transparent unions
mjbshaw 541934e
Add missing "union" word
mjbshaw 8c92dec
Add some initial text about transparent enums
mjbshaw 18ecba9
s/method/function/
mjbshaw 26d47b7
Fix indentation
mjbshaw 4c88177
Document the behavior of nonnull-style optimization
mjbshaw ce8b569
Fix typo: union -> enum
Centril 1488266
Mention that FFI can lead to UB if values are uninit
mjbshaw 2afd342
Merge branch 'transparent_unions' of github.com:mjbshaw/rfcs into tra…
mjbshaw bf09395
RFC 2645
Centril File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
- Feature Name: transparent_unions | ||
- Start Date: 2019-02-13 | ||
- RFC PR: | ||
- Rust Issue: | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Allow `#[repr(transparent)]` on `union`s that have exactly one non-zero-sized field (just like `struct`s). | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Some `union` types are thin newtype-style wrappers around another type, like `MaybeUninit<T>` (and [once upon a time](https://doc.rust-lang.org/1.26.1/src/core/mem.rs.html#950), `ManuallyDrop<T>`). This type is intended to be used in the same places as `T`, but without being `#[repr(transparent)]` the actual compatibility between it and `T` is left unspecified. | ||
|
||
Making types like these `#[repr(transparent)]` would be useful in certain cases. For example, making a `union Wrapper<T>` transparent: | ||
|
||
- Clearly expresses the intent of the developer. | ||
- Protects against accidental violations of that intent (e.g., adding a new non-ZST field to a transparent union will result in a compiler error). | ||
- Makes a clear API guarantee that a `Wrapper<T>` can be transmuted to a `T`. | ||
|
||
Transparent `union`s are a nice complement to transparent `struct`s, and this RFC rounds out the `#[repr(transparent)]` feature. | ||
|
||
# Guide-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
A `union` may be `#[repr(transparent)]` in exactly the same conditions in which a struct may be `#[repr(transparent)]`. Some concrete illustrations follow. | ||
|
||
A union may be `#[repr(transparent)]` if it has exactly one non-zero-sized field: | ||
|
||
```rust | ||
// This union has the same representation as `usize`. | ||
#[repr(transparent)] | ||
union CustomUnion { | ||
field: usize, | ||
nothing: (), | ||
} | ||
``` | ||
|
||
If the `union` is generic over `T` and has a field of type `T`, it may also be `#[repr(transparent)]` (even if `T` is a zero-sized type): | ||
|
||
```rust | ||
// This union has the same representation as `T`. | ||
#[repr(transparent)] | ||
pub union GenericUnion<T: Copy> { // Unions with non-`Copy` fields are unstable. | ||
pub field: T, | ||
pub nothing: (), | ||
} | ||
|
||
// This is okay even though `()` is a zero-sized type. | ||
pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () }; | ||
``` | ||
|
||
# Reference-level explanation | ||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
The logic controlling whether a `union` of type `U` may be `#[repr(transparent)]` should match the logic controlling whether a `struct` of type `S` may be `#[repr(transparent)]` (assuming `U` and `S` have the same generic parameters and fields). | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
- `#[repr(transparent)]` on a `union` is of limited use. There are cases where it is useful, but they're not common and some users might unnecessarily apply `#[repr(transparent)]` to a `union`. | ||
|
||
# Rationale and alternatives | ||
[alternatives]: #alternatives | ||
|
||
It would be nice to make `MaybeUninit<T>` `#[repr(transparent)]`. This type is a `union`, and thus this RFC is required in order to allow making it transparent. | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Of course, the standard "do nothing" alternative exists. Rust doesn't strictly *require* this feature. But it would benefit from this, so the "do nothing" alternative is undesirable. | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Prior art | ||
[prior-art]: #prior-art | ||
|
||
See [the discussion on RFC #1758](https://github.com/rust-lang/rfcs/pull/1758) (which introduced `#[repr(transparent)]`) for some discussion on applying the attribute to a `union`. A summary of the discussion: | ||
|
||
> https://github.com/rust-lang/rfcs/pull/1758#discussion_r80436621 | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **nagisa:** "Why not univariant unions and enums?" | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **nox:** "I tried to be conservative for now given I don't have a use case for univariant unions and enums in FFI context." | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
> https://github.com/rust-lang/rfcs/pull/1758#issuecomment-254872520 | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **eddyb:** "I found another important usecase: for `ManuallyDrop<T>`, to be useful in arrays (i.e. small vector optimizations), it needs to have the same layout as `T` and AFAICT `#[repr(C)]` is not guaranteed to do the right thing" | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **retep998:** "So we'd need to be able to specify `#[repr(transparent)]` on unions?" | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **eddyb:** "That's the only way to be sure AFAICT, yes." | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
> https://github.com/rust-lang/rfcs/pull/1758#issuecomment-274670231 | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **joshtriplett:** "In terms of interactions with other features, I think this needs to specify what happens if you apply it to a union with one field, a union with multiple fields, a struct (tuple or otherwise) with multiple fields, a single-variant enum with one field, an enum struct variant where the enum uses `repr(u32)` or similar. The answer to some of those might be "compile error", but some of them (e.g. the union case) may potentially make sense in some contexts." | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
> https://github.com/rust-lang/rfcs/pull/1758#issuecomment-290757356 | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> **pnkfelix:** "However, I personally do not think we need to expand the scope of the feature. So I am okay with leaving it solely defined on `struct`, and leave `union`/`enum` to a follow-on RFC later. (Much the same with a hypothetical `newtype` feature.)" | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
In summary, many of the questions regarding `#[repr(transparent)]` on a `union` were the same as applying it to a multi-field `struct`. These questions have since been answered, and I see no problems with applying those same answers to `union`. | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
None (yet). | ||
|
||
# Future possibilities | ||
[future-possibilities]: #future-possibilities | ||
|
||
Univariant `enum`s are ommitted from this RFC in an effort to keep the scope small and avoid unnecessary bikeshedding. A future RFC could explore `#[repr(transparent)]` on a univariant `enum`. | ||
Centril marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
If a `union` has multiple non-ZST fields, a future RFC could propose a way to choose the representation of that enum ([example](https://internals.rust-lang.org/t/pre-rfc-transparent-unions/9441/6)). | ||
mjbshaw marked this conversation as resolved.
Show resolved
Hide resolved
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.