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

update union field type rules #1238

Merged
merged 1 commit into from
Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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