update union field type rules

This commit is contained in:
Ralf Jung 2022-07-17 08:45:34 -04:00
parent d4d5dfd2c1
commit 969e45e09c
2 changed files with 22 additions and 30 deletions

View File

@ -20,6 +20,16 @@ The key property of unions is that all fields of a union share common storage.
As a result, writes to one field of a union can overwrite its other fields, and
size of a union is determined by the size of its largest field.
Union field types are restricted to the following subset of types:
- `Copy` types
- References (`&T` and `&mut T` for arbitrary `T`)
- `ManuallyDrop<T>` (for arbitrary `T`)
- Tuples and arrays containing only allowed union field types
This restriction ensures, in particular, that union fields never need to be
dropped. Like for structs and enums, it is possible to `impl Drop` for a union
to manually define what happens when it gets dropped.
## Initialization of a union
A value of a union type can be created using the same syntax that is used for
@ -67,32 +77,13 @@ unsafe {
}
```
Writes to [`Copy`] or [`ManuallyDrop`][ManuallyDrop] union fields do not
require reads for running destructors, so these writes don't have to be placed
in `unsafe` blocks
```rust
# use std::mem::ManuallyDrop;
union MyUnion { f1: u32, f2: ManuallyDrop<String> }
let mut u = MyUnion { f1: 1 };
// These do not require `unsafe`.
u.f1 = 2;
u.f2 = ManuallyDrop::new(String::from("example"));
```
Commonly, code using unions will provide safe wrappers around unsafe union
field accesses.
## Unions and `Drop`
When a union is dropped, it cannot know which of its fields needs to be dropped.
For this reason, all union fields must either be of a [`Copy`] type or of the
shape [`ManuallyDrop<_>`][ManuallyDrop]. This ensures that a union does not
need to drop anything when it goes out of scope.
Like for structs and enums, it is possible to `impl Drop` for a union to
manually define what happens when it gets dropped.
In contrast, writes to union fields are safe, since they just overwrite
arbitrary data, but cannot cause undefined behavior. (Note that union field
types can never have drop glue, so a union field write will never implicitly
drop anything.)
## Pattern matching on unions

View File

@ -4,14 +4,15 @@ A *union type* is a nominal, heterogeneous C-like union, denoted by the name of
a [`union` item][item].
Unions have no notion of an "active field". Instead, every union access
transmutes parts of the content of the union to the type of the accessed
field. Since transmutes can cause unexpected or undefined behaviour, `unsafe`
is required to read from a union field, or to write to a field that doesn't
implement [`Copy`] or has a [`ManuallyDrop`] type. See the [item] documentation
for further details.
transmutes parts of the content of the union to the type of the accessed field.
Since transmutes can cause unexpected or undefined behaviour, `unsafe` is
required to read from a union field. Union field types are also restricted to a
subset of types which ensures that they never need dropping. See the [item]
documentation for further details.
The memory layout of a `union` is undefined by default, but the `#[repr(...)]`
attribute can be used to fix a layout.
The memory layout of a `union` is undefined by default (in particular, fields do
*not* have to be at offset 0), but the `#[repr(...)]` attribute can be used to
fix a layout.
[`Copy`]: ../special-types-and-traits.md#copy
[`ManuallyDrop`]: ../../std/mem/struct.ManuallyDrop.html