Skip to content

Commit

Permalink
Disable dead variant removal for #[repr(C)] enums.
Browse files Browse the repository at this point in the history
  • Loading branch information
GoldsteinE committed Jun 28, 2024
1 parent 1a851da commit 71dfbea
Show file tree
Hide file tree
Showing 10 changed files with 1,548 additions and 3 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ pub trait LayoutCalculator {
let (present_first, present_second) = {
let mut present_variants = variants
.iter_enumerated()
.filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
.filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) });
(present_variants.next(), present_variants.next())
};
let present_first = match present_first {
Expand Down Expand Up @@ -621,7 +621,7 @@ where
let discr_type = repr.discr_type();
let bits = Integer::from_attr(dl, discr_type).size().bits();
for (i, mut val) in discriminants {
if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
continue;
}
if discr_type.is_signed() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },

/// Enum-likes with more than one inhabited variant: each variant comes with
/// Enum-likes with more than one variant: each variant comes with
/// a *discriminant* (usually the same as the variant index but the user can
/// assign explicit discriminant values). That discriminant is encoded
/// as a *tag* on the machine. The layout of each variant is
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/abi/compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ test_abi_compatible!(zst_unit, Zst, ());
test_abi_compatible!(zst_array, Zst, [u8; 0]);
test_abi_compatible!(nonzero_int, NonZero<i32>, i32);

// `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness.
enum Void {}
test_abi_compatible!(repr_c_enum_void, ReprCEnum<Void>, ReprCEnum<ReprCUnion<Void>>);

// `DispatchFromDyn` relies on ABI compatibility.
// This is interesting since these types are not `repr(transparent)`. So this is not part of our
// public ABI guarantees, but is relied on by the compiler.
Expand Down
288 changes: 288 additions & 0 deletions tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
error: layout_of(Univariant) = Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 0..=0,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I32,
false,
),
valid_range: 0..=0,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(4 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/repr-c-dead-variants.rs:38:1
|
LL | enum Univariant {
| ^^^^^^^^^^^^^^^

error: layout_of(TwoVariants) = Layout {
size: Size(8 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: $SOME_ALIGN,
},
abi: ScalarPair(
Initialized {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
Union {
value: Int(
I8,
false,
),
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(4 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
},
Layout {
size: Size(8 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: $SOME_ALIGN,
},
abi: ScalarPair(
Initialized {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
Union {
value: Int(
I8,
false,
),
},
),
fields: Arbitrary {
offsets: [
Size(4 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/repr-c-dead-variants.rs:45:1
|
LL | enum TwoVariants {
| ^^^^^^^^^^^^^^^^

error: layout_of(DeadBranchHasOtherField) = Layout {
size: Size(16 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: $SOME_ALIGN,
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(16 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(8 bytes),
Size(8 bytes),
],
memory_index: [
0,
1,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: Some(
Align(8 bytes),
),
unadjusted_abi_align: Align(8 bytes),
},
Layout {
size: Size(16 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: $SOME_ALIGN,
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [
Size(8 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
},
],
},
max_repr_align: Some(
Align(8 bytes),
),
unadjusted_abi_align: Align(8 bytes),
}
--> $DIR/repr-c-dead-variants.rs:57:1
|
LL | enum DeadBranchHasOtherField {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

Loading

0 comments on commit 71dfbea

Please sign in to comment.