@@ -6,29 +6,99 @@ not to change until an RFC ratifies them.
6
6
7
7
[ #13 ] : https://github.com/rust-rfcs/unsafe-code-guidelines/issues/13
8
8
9
- The only degree of freedom the compiler has when computing the layout of a union
10
- like
9
+ ### Layout of individual union fields
11
10
12
- ``` rust,ignore
13
- union U { f1: T1, f2: T2 }
11
+ The layout of each union field is determined by its type.
12
+
13
+ <details ><summary ><b >Rationale</b ></summary >
14
+
15
+ This is required to allow creating references to union fields:
16
+
17
+ ``` rust
18
+ # fn main () { unsafe {
19
+ # #[derive(Copy , Clone )]
20
+ struct T1 ;
21
+ union U { f1 : T1 }
22
+ let u = U { f1 : T1 };
23
+ let t1 : & T1 = & u . f1;
24
+ // &T1 works for all references
25
+ # }}
14
26
```
27
+ </details >
15
28
16
- is to determine the offset of the fields. The layout of these fields themselves
17
- is already entirely determined by their types, and since we intend to allow
18
- creating references to fields (` &u.f1 ` ), unions do not have any wiggle-room
19
- there.
29
+ ### Unions with default layout ("` repr(Rust) ` ")
20
30
21
- ### Default layout ("repr rust")
31
+ ** The default layout of unions is ** , in general, ** not specified. **
22
32
23
- ** The default layout of unions is not specified.** As of this writing, we want
24
- to keep the option of using non-zero offsets open for the future; whether this
25
- is useful depends on what exactly the compiler-assumed invariants about union
26
- contents are.
33
+ <details ><summary ><b >Rationale</b ></summary >
34
+
35
+ As of this writing, we want to keep the option of using non-zero offsets open
36
+ for the future; whether this is useful depends on what exactly the
37
+ compiler-assumed invariants about union contents are. This might become clearer
38
+ after the validity of unions
39
+ ([ unsafe-code-guidelines/73] ( https://github.com/rust-lang/unsafe-code-guidelines/issues/73 ) )
40
+ is settled.
27
41
28
42
Even if the offsets happen to be all 0, there might still be differences in the
29
43
function call ABI. If you need to pass unions by-value across an FFI boundary,
30
44
you have to use ` #[repr(C)] ` .
31
45
46
+ </details >
47
+
48
+ #### Layout of unions with a single non-zero-sized field
49
+
50
+ The layout of unions with a single non-zero-sized field is the same as the
51
+ layout of that field if:
52
+
53
+ * that field has no padding bits, and
54
+ * the alignment requirement of all zero-sized fields is 1.
55
+
56
+ For example, here:
57
+
58
+ ``` rust
59
+ # use std :: mem :: {size_of, align_of};
60
+ # #[derive(Copy , Clone )]
61
+ #[repr(transparent)]
62
+ struct SomeStruct (i32 );
63
+ # #[derive(Copy , Clone )]
64
+ struct Zst ;
65
+ union U0 {
66
+ f0 : SomeStruct ,
67
+ f1 : Zst ,
68
+ }
69
+ # fn main () {
70
+ # assert_eq! (size_of :: <U0 >(), size_of :: <SomeStruct >());
71
+ # assert_eq! (align_of :: <U0 >(), align_of :: <SomeStruct >());
72
+ # }
73
+ ```
74
+
75
+ the union ` U0 ` has the same layout as ` SomeStruct ` , because ` SomeStruct ` has no
76
+ padding bits - it is equivalent to an ` i32 ` due to ` repr(transparent) ` - and
77
+ because the alignment of ` Zst ` is 1.
78
+
79
+ On the other hand, here:
80
+
81
+ ``` rust
82
+ # use std :: mem :: {size_of, align_of};
83
+ # #[derive(Copy , Clone )]
84
+ struct SomeOtherStruct (i32 );
85
+ # #[derive(Copy , Clone )]
86
+ #[repr(align(16))] struct Zst2 ;
87
+ union U1 {
88
+ f0 : SomeOtherStruct ,
89
+ f1 : Zst2 ,
90
+ }
91
+ # fn main () {
92
+ # assert_eq! (size_of :: <U1 >(), align_of :: <Zst2 >());
93
+ # assert_eq! (align_of :: <U1 >(), align_of :: <Zst2 >());
94
+ assert_eq! (align_of :: <Zst2 >(), 16 );
95
+ # }
96
+ ```
97
+
98
+ the alignment requirement of ` Zst2 ` is not 1, and ` SomeOtherStruct ` has an
99
+ unspecified layout and could contain padding bits. Therefore, the layout of ` U1 `
100
+ is ** unspecified** .
101
+
32
102
### C-compatible layout ("repr C")
33
103
34
104
The layout of ` repr(C) ` unions follows the C layout scheme. Per sections
0 commit comments