Rollup merge of #123043 - GoldsteinE:fix/repr-c-dead-branches, r=oli-obk

Disable dead variant removal for `#[repr(C)]` enums.

This prevents removing dead branches from a `#[repr(C)]` enum (they now get discriminants allocated as if they were inhabited).

Implementation notes: ABI of something like

```rust
#[repr(C)]
enum Foo {
    Foo(!),
}
```

is still `Uninhabited`, but its layout is now computed as if all the branches were inhabited.
This seemed to me like a proper way to do it, especially given that ABI sanity check explicitly asserts that type-level uninhabitedness implies ABI uninhabitedness.

This probably needs some sort of FCP (given that it changes `#[repr(C)]` layout, which is a stable guarantee), but I’m not sure how to call for one or which team is the most relevant.

See https://github.com/rust-lang/unsafe-code-guidelines/issues/500.
This commit is contained in:
Matthias Krüger 2024-07-04 18:16:22 +02:00 committed by GitHub
commit f0a0f8f7e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1549 additions and 3 deletions

View File

@ -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 {
@ -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() {

View File

@ -1429,7 +1429,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

View File

@ -271,6 +271,11 @@ 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.
// (However, this is *not* a guarantee. We only guarantee same layout, not same ABI.)
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.

View File

@ -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

View File

@ -0,0 +1,288 @@
error: layout_of(Univariant) = Layout {
size: Size(1 bytes),
align: AbiAndPrefAlign {
abi: Align(1 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(
I8,
false,
),
valid_range: 0..=0,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=0,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(1 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(1 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
}
--> $DIR/repr-c-dead-variants.rs:38:1
|
LL | enum Univariant {
| ^^^^^^^^^^^^^^^
error: layout_of(TwoVariants) = Layout {
size: Size(2 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: ScalarPair(
Initialized {
value: Int(
I8,
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(
I8,
false,
),
valid_range: 0..=1,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(1 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(1 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
Layout {
size: Size(2 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: ScalarPair(
Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
Union {
value: Int(
I8,
false,
),
},
),
fields: Arbitrary {
offsets: [
Size(1 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(1 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(
I8,
false,
),
valid_range: 0..=1,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
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

View File

@ -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

View File

@ -0,0 +1,63 @@
#![feature(no_core, rustc_attrs, lang_items)]
#![allow(dead_code)]
#![crate_type = "lib"]
#![no_std]
#![no_core]
// See also: repr-c-int-dead-variants.rs
//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
// This test depends on the value of the `c_enum_min_bits` target option.
// As there's no way to actually check it from UI test, we only run this test on a subset of archs.
// Four archs specifically are chosen: one for major architectures (x86_64, i686, aarch64)
// and `armebv7r-none-eabi` that has `c_enum_min_bits` set to 8.
//@ revisions: aarch64-unknown-linux-gnu
//@[aarch64-unknown-linux-gnu] compile-flags: --target aarch64-unknown-linux-gnu
//@[aarch64-unknown-linux-gnu] needs-llvm-components: aarch64
//@ revisions: i686-pc-windows-msvc
//@[i686-pc-windows-msvc] compile-flags: --target i686-pc-windows-gnu
//@[i686-pc-windows-msvc] needs-llvm-components: x86
//@ revisions: x86_64-unknown-linux-gnu
//@[x86_64-unknown-linux-gnu] compile-flags: --target x86_64-unknown-linux-gnu
//@[x86_64-unknown-linux-gnu] needs-llvm-components: x86
//
//@ revisions: armebv7r-none-eabi
//@[armebv7r-none-eabi] compile-flags: --target armebv7r-none-eabi
//@[armebv7r-none-eabi] needs-llvm-components: arm
// A simple uninhabited type.
enum Void {}
// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
#[repr(C)]
#[rustc_layout(debug)]
enum Univariant { //~ ERROR layout_of
Variant(Void),
}
// ADTs with variants that have fields must have space allocated for those fields.
#[repr(C)]
#[rustc_layout(debug)]
enum TwoVariants { //~ ERROR layout_of
Variant1(Void),
Variant2(u8),
}
// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned.
#[repr(C, align(8))]
struct Align8U64(u64);
// This one is 2 x u64: we reserve space for fields in a dead branch.
#[repr(C)]
#[rustc_layout(debug)]
enum DeadBranchHasOtherField { //~ ERROR layout_of
Variant1(Void, Align8U64),
Variant2(u8),
}
#[lang = "sized"]
trait Sized {}

View File

@ -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

View File

@ -0,0 +1,38 @@
#![feature(rustc_attrs)]
#![allow(dead_code)]
// See also: repr-c-dead-variants.rs
//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
// A simple uninhabited type.
enum Void {}
// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
#[repr(C, u8)]
#[rustc_layout(debug)]
enum UnivariantU8 { //~ ERROR layout_of
Variant(Void),
}
// ADTs with variants that have fields must have space allocated for those fields.
#[repr(C, u8)]
#[rustc_layout(debug)]
enum TwoVariantsU8 { //~ ERROR layout_of
Variant1(Void),
Variant2(u8),
}
// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned.
#[repr(C, align(8))]
struct Align8U64(u64);
// This one is 2 x u64: we reserve space for fields in a dead branch.
#[repr(C, u8)]
#[rustc_layout(debug)]
enum DeadBranchHasOtherFieldU8 { //~ ERROR layout_of
Variant1(Void, Align8U64),
Variant2(u8),
}
fn main() {}

View File

@ -0,0 +1,288 @@
error: layout_of(UnivariantU8) = Layout {
size: Size(1 bytes),
align: AbiAndPrefAlign {
abi: Align(1 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(
I8,
false,
),
valid_range: 0..=0,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=0,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(1 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(1 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
}
--> $DIR/repr-c-int-dead-variants.rs:14:1
|
LL | enum UnivariantU8 {
| ^^^^^^^^^^^^^^^^^
error: layout_of(TwoVariantsU8) = Layout {
size: Size(2 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: ScalarPair(
Initialized {
value: Int(
I8,
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(
I8,
false,
),
valid_range: 0..=1,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
tag_encoding: Direct,
tag_field: 0,
variants: [
Layout {
size: Size(1 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: Uninhabited,
fields: Arbitrary {
offsets: [
Size(1 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
Layout {
size: Size(2 bytes),
align: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: $SOME_ALIGN,
},
abi: ScalarPair(
Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=1,
},
Union {
value: Int(
I8,
false,
),
},
),
fields: Arbitrary {
offsets: [
Size(1 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
}
--> $DIR/repr-c-int-dead-variants.rs:21:1
|
LL | enum TwoVariantsU8 {
| ^^^^^^^^^^^^^^^^^^
error: layout_of(DeadBranchHasOtherFieldU8) = 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(
I8,
false,
),
valid_range: 0..=1,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
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-int-dead-variants.rs:33:1
|
LL | enum DeadBranchHasOtherFieldU8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors