diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index a95ef4c460f..aff0d70bf90 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -186,7 +186,7 @@ fn layout_of_struct_or_enum< 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 @@ struct TmpLayout { 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() { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 5e3f64540e4..1e5e391d19b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1401,7 +1401,7 @@ pub enum Variants { /// 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 diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 373d1cce1d7..086177efb77 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -277,6 +277,10 @@ mod $name { test_abi_compatible!(zst_array, Zst, [u8; 0]); test_abi_compatible!(nonzero_int, NonZero, i32); +// `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness. +enum Void {} +test_abi_compatible!(repr_c_enum_void, ReprCEnum, ReprCEnum>); + // `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. diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr new file mode 100644 index 00000000000..e2e57fe0e73 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -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 + diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr new file mode 100644 index 00000000000..6ecdab1cc14 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -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 + diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr new file mode 100644 index 00000000000..e2e57fe0e73 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -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 + diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs new file mode 100644 index 00000000000..f113588e83f --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.rs @@ -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 {} diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr new file mode 100644 index 00000000000..e2e57fe0e73 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -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 + diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs new file mode 100644 index 00000000000..8d2b39bd648 --- /dev/null +++ b/tests/ui/repr/repr-c-int-dead-variants.rs @@ -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() {} diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr new file mode 100644 index 00000000000..f7df576df24 --- /dev/null +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -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 +