@@ -6,17 +6,98 @@ 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
+ # }}
26
+ ```
27
+ </details >
28
+
29
+ ### Unions with default layout ("` repr(Rust) ` ")
30
+
31
+ ** The default layout of unions is** , in general, ** not specified.**
32
+
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.
41
+
42
+ Even if the offsets happen to be all 0, there might still be differences in the
43
+ function call ABI. If you need to pass unions by-value across an FFI boundary,
44
+ you have to use ` #[repr(C)] ` .
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
+ # }
14
96
```
15
97
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.
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** .
20
101
21
102
### C-compatible layout ("repr C")
22
103
@@ -27,14 +108,3 @@ a field type to obtain a pointer to any field, and vice versa.
27
108
28
109
[ 6.5.8.5 ] : http://port70.net/~nsz/c/c11/n1570.html#6.5.8p5
29
110
[ 6.7.2.1.16 ] : http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p16
30
-
31
- ### Default layout ("repr rust")
32
-
33
- ** The default layout of unions is not specified.** As of this writing, we want
34
- to keep the option of using non-zero offsets open for the future; whether this
35
- is useful depends on what exactly the compiler-assumed invariants about union
36
- contents are.
37
-
38
- Even if the offsets happen to be all 0, there might still be differences in the
39
- function call ABI. If you need to pass unions by-value across an FFI boundary,
40
- you have to use ` #[repr(C)] ` .
0 commit comments