Skip to content

Commit 71dfbea

Browse files
committed
Disable dead variant removal for #[repr(C)] enums.
See rust-lang/unsafe-code-guidelines#500.
1 parent 1a851da commit 71dfbea

10 files changed

+1548
-3
lines changed

compiler/rustc_abi/src/layout.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ pub trait LayoutCalculator {
186186
let (present_first, present_second) = {
187187
let mut present_variants = variants
188188
.iter_enumerated()
189-
.filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
189+
.filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) });
190190
(present_variants.next(), present_variants.next())
191191
};
192192
let present_first = match present_first {
@@ -621,7 +621,7 @@ where
621621
let discr_type = repr.discr_type();
622622
let bits = Integer::from_attr(dl, discr_type).size().bits();
623623
for (i, mut val) in discriminants {
624-
if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
624+
if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
625625
continue;
626626
}
627627
if discr_type.is_signed() {

compiler/rustc_abi/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
14011401
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
14021402
Single { index: VariantIdx },
14031403

1404-
/// Enum-likes with more than one inhabited variant: each variant comes with
1404+
/// Enum-likes with more than one variant: each variant comes with
14051405
/// a *discriminant* (usually the same as the variant index but the user can
14061406
/// assign explicit discriminant values). That discriminant is encoded
14071407
/// as a *tag* on the machine. The layout of each variant is

tests/ui/abi/compatibility.rs

+4
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ test_abi_compatible!(zst_unit, Zst, ());
277277
test_abi_compatible!(zst_array, Zst, [u8; 0]);
278278
test_abi_compatible!(nonzero_int, NonZero<i32>, i32);
279279

280+
// `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness.
281+
enum Void {}
282+
test_abi_compatible!(repr_c_enum_void, ReprCEnum<Void>, ReprCEnum<ReprCUnion<Void>>);
283+
280284
// `DispatchFromDyn` relies on ABI compatibility.
281285
// This is interesting since these types are not `repr(transparent)`. So this is not part of our
282286
// public ABI guarantees, but is relied on by the compiler.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
error: layout_of(Univariant) = Layout {
2+
size: Size(4 bytes),
3+
align: AbiAndPrefAlign {
4+
abi: Align(4 bytes),
5+
pref: $SOME_ALIGN,
6+
},
7+
abi: Uninhabited,
8+
fields: Arbitrary {
9+
offsets: [
10+
Size(0 bytes),
11+
],
12+
memory_index: [
13+
0,
14+
],
15+
},
16+
largest_niche: Some(
17+
Niche {
18+
offset: Size(0 bytes),
19+
value: Int(
20+
I32,
21+
false,
22+
),
23+
valid_range: 0..=0,
24+
},
25+
),
26+
variants: Multiple {
27+
tag: Initialized {
28+
value: Int(
29+
I32,
30+
false,
31+
),
32+
valid_range: 0..=0,
33+
},
34+
tag_encoding: Direct,
35+
tag_field: 0,
36+
variants: [
37+
Layout {
38+
size: Size(4 bytes),
39+
align: AbiAndPrefAlign {
40+
abi: Align(4 bytes),
41+
pref: $SOME_ALIGN,
42+
},
43+
abi: Uninhabited,
44+
fields: Arbitrary {
45+
offsets: [
46+
Size(4 bytes),
47+
],
48+
memory_index: [
49+
0,
50+
],
51+
},
52+
largest_niche: None,
53+
variants: Single {
54+
index: 0,
55+
},
56+
max_repr_align: None,
57+
unadjusted_abi_align: Align(4 bytes),
58+
},
59+
],
60+
},
61+
max_repr_align: None,
62+
unadjusted_abi_align: Align(4 bytes),
63+
}
64+
--> $DIR/repr-c-dead-variants.rs:38:1
65+
|
66+
LL | enum Univariant {
67+
| ^^^^^^^^^^^^^^^
68+
69+
error: layout_of(TwoVariants) = Layout {
70+
size: Size(8 bytes),
71+
align: AbiAndPrefAlign {
72+
abi: Align(4 bytes),
73+
pref: $SOME_ALIGN,
74+
},
75+
abi: ScalarPair(
76+
Initialized {
77+
value: Int(
78+
I32,
79+
false,
80+
),
81+
valid_range: 0..=1,
82+
},
83+
Union {
84+
value: Int(
85+
I8,
86+
false,
87+
),
88+
},
89+
),
90+
fields: Arbitrary {
91+
offsets: [
92+
Size(0 bytes),
93+
],
94+
memory_index: [
95+
0,
96+
],
97+
},
98+
largest_niche: Some(
99+
Niche {
100+
offset: Size(0 bytes),
101+
value: Int(
102+
I32,
103+
false,
104+
),
105+
valid_range: 0..=1,
106+
},
107+
),
108+
variants: Multiple {
109+
tag: Initialized {
110+
value: Int(
111+
I32,
112+
false,
113+
),
114+
valid_range: 0..=1,
115+
},
116+
tag_encoding: Direct,
117+
tag_field: 0,
118+
variants: [
119+
Layout {
120+
size: Size(4 bytes),
121+
align: AbiAndPrefAlign {
122+
abi: Align(4 bytes),
123+
pref: $SOME_ALIGN,
124+
},
125+
abi: Uninhabited,
126+
fields: Arbitrary {
127+
offsets: [
128+
Size(4 bytes),
129+
],
130+
memory_index: [
131+
0,
132+
],
133+
},
134+
largest_niche: None,
135+
variants: Single {
136+
index: 0,
137+
},
138+
max_repr_align: None,
139+
unadjusted_abi_align: Align(4 bytes),
140+
},
141+
Layout {
142+
size: Size(8 bytes),
143+
align: AbiAndPrefAlign {
144+
abi: Align(4 bytes),
145+
pref: $SOME_ALIGN,
146+
},
147+
abi: ScalarPair(
148+
Initialized {
149+
value: Int(
150+
I32,
151+
false,
152+
),
153+
valid_range: 0..=1,
154+
},
155+
Union {
156+
value: Int(
157+
I8,
158+
false,
159+
),
160+
},
161+
),
162+
fields: Arbitrary {
163+
offsets: [
164+
Size(4 bytes),
165+
],
166+
memory_index: [
167+
0,
168+
],
169+
},
170+
largest_niche: None,
171+
variants: Single {
172+
index: 1,
173+
},
174+
max_repr_align: None,
175+
unadjusted_abi_align: Align(4 bytes),
176+
},
177+
],
178+
},
179+
max_repr_align: None,
180+
unadjusted_abi_align: Align(4 bytes),
181+
}
182+
--> $DIR/repr-c-dead-variants.rs:45:1
183+
|
184+
LL | enum TwoVariants {
185+
| ^^^^^^^^^^^^^^^^
186+
187+
error: layout_of(DeadBranchHasOtherField) = Layout {
188+
size: Size(16 bytes),
189+
align: AbiAndPrefAlign {
190+
abi: Align(8 bytes),
191+
pref: $SOME_ALIGN,
192+
},
193+
abi: Aggregate {
194+
sized: true,
195+
},
196+
fields: Arbitrary {
197+
offsets: [
198+
Size(0 bytes),
199+
],
200+
memory_index: [
201+
0,
202+
],
203+
},
204+
largest_niche: Some(
205+
Niche {
206+
offset: Size(0 bytes),
207+
value: Int(
208+
I32,
209+
false,
210+
),
211+
valid_range: 0..=1,
212+
},
213+
),
214+
variants: Multiple {
215+
tag: Initialized {
216+
value: Int(
217+
I32,
218+
false,
219+
),
220+
valid_range: 0..=1,
221+
},
222+
tag_encoding: Direct,
223+
tag_field: 0,
224+
variants: [
225+
Layout {
226+
size: Size(16 bytes),
227+
align: AbiAndPrefAlign {
228+
abi: Align(8 bytes),
229+
pref: $SOME_ALIGN,
230+
},
231+
abi: Uninhabited,
232+
fields: Arbitrary {
233+
offsets: [
234+
Size(8 bytes),
235+
Size(8 bytes),
236+
],
237+
memory_index: [
238+
0,
239+
1,
240+
],
241+
},
242+
largest_niche: None,
243+
variants: Single {
244+
index: 0,
245+
},
246+
max_repr_align: Some(
247+
Align(8 bytes),
248+
),
249+
unadjusted_abi_align: Align(8 bytes),
250+
},
251+
Layout {
252+
size: Size(16 bytes),
253+
align: AbiAndPrefAlign {
254+
abi: Align(8 bytes),
255+
pref: $SOME_ALIGN,
256+
},
257+
abi: Aggregate {
258+
sized: true,
259+
},
260+
fields: Arbitrary {
261+
offsets: [
262+
Size(8 bytes),
263+
],
264+
memory_index: [
265+
0,
266+
],
267+
},
268+
largest_niche: None,
269+
variants: Single {
270+
index: 1,
271+
},
272+
max_repr_align: None,
273+
unadjusted_abi_align: Align(8 bytes),
274+
},
275+
],
276+
},
277+
max_repr_align: Some(
278+
Align(8 bytes),
279+
),
280+
unadjusted_abi_align: Align(8 bytes),
281+
}
282+
--> $DIR/repr-c-dead-variants.rs:57:1
283+
|
284+
LL | enum DeadBranchHasOtherField {
285+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
286+
287+
error: aborting due to 3 previous errors
288+

0 commit comments

Comments
 (0)