From 969e45e09c68a167ecf456901f490cd6a21a70a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 08:45:34 -0400 Subject: [PATCH] update union field type rules --- src/items/unions.md | 37 ++++++++++++++----------------------- src/types/union.md | 15 ++++++++------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/items/unions.md b/src/items/unions.md index 7ad5da71e..325b22717 100644 --- a/src/items/unions.md +++ b/src/items/unions.md @@ -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` (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 } -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 diff --git a/src/types/union.md b/src/types/union.md index 3f96cc96d..326e720c6 100644 --- a/src/types/union.md +++ b/src/types/union.md @@ -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