You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow `#[repr(transparent)]` on `union`s that have exactly one non-zero-sized field (just like `struct`s).
9
+
Allow `#[repr(transparent)]` on `union`s an univariant `enum`s that have exactly one non-zero-sized field (just like `struct`s).
10
10
11
11
# Motivation
12
12
[motivation]: #motivation
13
13
14
-
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.
14
+
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.28.0/src/core/mem.rs.html#955), `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.
15
15
16
-
Making types like these `#[repr(transparent)]` would be useful in certain cases. For example, making a `union Wrapper<T>` transparent:
16
+
Likewise, some `enum` types only have a single variant, and are similarly thin wrappers around another type.
17
+
18
+
Making types like these `#[repr(transparent)]` would be useful in certain cases. For example, making the type `Wrapper<T>` (which is a `union` or univariant `enum` with a single field of type `T`) transparent:
17
19
18
20
- Clearly expresses the intent of the developer.
19
-
- 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).
20
-
- Makes a clear API guarantee that a `Wrapper<T>` can be transmuted to a `T`.
21
+
- Protects against accidental violations of that intent (e.g., adding a new variant or non-ZST field will result in a compiler error).
22
+
- Makes a clear API guarantee that a `Wrapper<T>` can be transmuted to a `T` or substituted for a `T` in an FFI function's signature.
21
23
22
-
Transparent `union`s are a nice complement to transparent `struct`s, and this RFC is a step towards rounding out the `#[repr(transparent)]` feature.
24
+
Transparent `union`s and univariant `enum`s are a nice complement to transparent `struct`s, and this RFC rounds out the `#[repr(transparent)]` feature.
A `union` may be `#[repr(transparent)]` in exactly the same conditions in which a struct may be `#[repr(transparent)]`. Some concrete illustrations follow.
29
+
A `union` may be `#[repr(transparent)]` in exactly the same conditions in which a `struct` may be `#[repr(transparent)]`. An `enum` may be `#[repr(transparent)]` if it has exactly one variant, and that variant matches the same conditions which `struct` requires for transparency. Some concrete illustrations follow.
28
30
29
31
A union may be `#[repr(transparent)]` if it has exactly one non-zero-sized field:
30
32
31
33
```rust
34
+
// This union has the same representation as `f32`.
35
+
#[repr(transparent)]
36
+
unionSingleFieldUnion {
37
+
field:f32,
38
+
}
39
+
32
40
// This union has the same representation as `usize`.
33
41
#[repr(transparent)]
34
-
unionCustomUnion {
42
+
unionMultiFieldUnion {
35
43
field:usize,
36
44
nothing: (),
37
45
}
46
+
47
+
// This enum has the same representation as `f32`.
48
+
#[repr(transparent)]
49
+
enumSingleFieldEnum {
50
+
Variant(f32)
51
+
}
52
+
53
+
// This enum has the same representation as `usize`.
54
+
#[repr(transparent)]
55
+
enumMultiFieldEnum {
56
+
Variant { field:usize, nothing: () },
57
+
}
38
58
```
39
59
40
-
For consistency with transparent `struct`s, a `union`must have exactly one non-zero-sized field. If all fields are zero-sized, the `union` must not be `#[repr(transparent)]`:
60
+
For consistency with transparent `struct`s, `union`s and `enum`s must have exactly one non-zero-sized field. If all fields are zero-sized, the `union` or `enum` must not be `#[repr(transparent)]`:
41
61
42
62
```rust
43
63
// This (non-transparent) union is already valid in stable Rust:
44
-
pubunionGood {
64
+
pubunionGoodUnion {
45
65
pubnothing: (),
46
66
}
47
67
68
+
// This (non-transparent) enum is already valid in stable Rust:
69
+
pubenumGoodEnum {
70
+
Nothing,
71
+
}
72
+
48
73
// Error: transparent union needs exactly one non-zero-sized field, but has 0
49
74
#[repr(transparent)]
50
-
pubunionBad {
75
+
pubunionBadUnion {
51
76
pubnothing: (),
52
77
}
78
+
79
+
// Error: transparent enum needs exactly one non-zero-sized field, but has 0
80
+
#[repr(transparent)]
81
+
pubenumBadEnum {
82
+
Nothing(()),
83
+
}
84
+
85
+
// Error: transparent enum needs exactly one non-zero-sized field, but has 0
86
+
#[repr(transparent)]
87
+
pubenumBadEmptyEnum {
88
+
Nothing,
89
+
}
53
90
```
54
91
55
-
The one exception is if the `union` is generic over `T` and has a field of type `T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:
92
+
The one exception is if the `union`or `enum`is generic over `T` and has a field of type `T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:
56
93
57
94
```rust
58
95
// This union has the same representation as `T`.
@@ -62,29 +99,103 @@ pub union GenericUnion<T: Copy> { // Unions with non-`Copy` fields are unstable.
62
99
pubnothing: (),
63
100
}
64
101
102
+
// This enum has the same representation as `T`.
103
+
#[repr(transparent)]
104
+
pubenumGenericEnum<T> {
105
+
Variant(T, ()),
106
+
}
107
+
65
108
// This is okay even though `()` is a zero-sized type.
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).
132
+
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). An `enum` of type `E` may be `#[repr(transparent)]` if it has exactly one variant, and that variant follows all the rules and logic controlling whether a `struct` of type `S` may be `#[repr(transparent)]` (assuming `E` and `S` have the same generic parameters, and `E`'s variant and `S` have the same and fields).
133
+
134
+
Like transarent `struct`s, a transparent `union` of type `U` and transparent `enum` of type `E` have the same layout, size, and ABI as their single non-ZST field. If they are generic over a type `T`, and all their fields are ZSTs except for exactly one field of type `T`, then they have the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).
135
+
136
+
Like transparent `struct`s, transparent `union`s and `enum`s are FFI-safe if and only if their underlying representation type is also FFI-safe.
73
137
74
138
# Drawbacks
75
139
[drawbacks]: #drawbacks
76
140
77
-
-`#[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`.
141
+
`#[repr(transparent)]` on a `union`or `enum`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 type in a cargo-cult fashion.
78
142
79
143
# Rationale and alternatives
80
144
[alternatives]: #alternatives
81
145
82
-
It would be nice to make `MaybeUninit<T>``#[repr(transparent)]`. This type is a `union`, and thus this RFC is required to allow making it transparent.
146
+
It would be nice to make `MaybeUninit<T>``#[repr(transparent)]`. This type is a `union`, and thus this RFC is required to allow making it transparent. One example in which a transparent representation would be useful is for unused parameters in an FFI-function:
147
+
148
+
```rust
149
+
#[repr(C)]
150
+
structContext {
151
+
// Imagine there a few fields here, defined by an external C library.
// Initialize the cryptor and return whether we succeeded
192
+
}
193
+
```
83
194
84
195
# Prior art
85
196
[prior-art]: #prior-art
86
197
87
-
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:
198
+
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` or `enum`. A summary of the discussion:
> +**[pnkfelix][pnkfelix_1]:** "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.)"
103
214
104
-
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, so there should be no problems with applying those same answers to `union`.
215
+
In summary, many of the questions regarding `#[repr(transparent)]` on a `union`or `enum`were the same as applying it to a multi-field `struct`. These questions have since been answered, so there should be no problems with applying those same answers to `union` univariant `enum`.
105
216
106
217
# Unresolved questions
107
218
[unresolved]: #unresolved-questions
@@ -111,6 +222,4 @@ None (yet).
111
222
# Future possibilities
112
223
[future-possibilities]: #future-possibilities
113
224
114
-
Univariant `enum`s are ommitted from this RFC in an effort to keep the scope small. A future RFC could explore `#[repr(transparent)]` on a univariant `enum`.
115
-
116
225
If a `union` has multiple non-ZST fields, a future RFC could propose a way to choose the representation of that `union` ([example](https://internals.rust-lang.org/t/pre-rfc-transparent-unions/9441/6)).
0 commit comments