Skip to content

Commit

Permalink
update union field type rules
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jul 17, 2022
1 parent d4d5dfd commit 969e45e
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 30 deletions.
37 changes: 14 additions & 23 deletions src/items/unions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
15 changes: 8 additions & 7 deletions src/types/union.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 969e45e

Please sign in to comment.