From cedc428a5fa988a3d7639a0fa45b726e0fd698ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 May 2022 15:01:25 +0200 Subject: [PATCH 1/2] fix the layout of repr(align) enums --- compiler/rustc_middle/src/ty/layout.rs | 6 +- src/test/ui/aligned_enum_cast.rs | 10 +- .../ui/layout/issue-96185-overaligned-enum.rs | 19 ++ .../issue-96185-overaligned-enum.stderr | 172 ++++++++++++++++++ 4 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/layout/issue-96185-overaligned-enum.rs create mode 100644 src/test/ui/layout/issue-96185-overaligned-enum.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 3b05e42a53ead..e20f94b15c6ac 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1418,9 +1418,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { abi = Abi::Uninhabited; - } else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) { - // Without latter check aligned enums with custom discriminant values - // Would result in ICE see the issue #92464 for more info + } else if tag.size(dl) == size { + // Make sure we only use scalar layout when the enum is entirely its + // own tag (i.e. it has no padding nor any non-ZST variant fields). abi = Abi::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. diff --git a/src/test/ui/aligned_enum_cast.rs b/src/test/ui/aligned_enum_cast.rs index 4b5776a6aa8ee..7fbfc760d09c8 100644 --- a/src/test/ui/aligned_enum_cast.rs +++ b/src/test/ui/aligned_enum_cast.rs @@ -11,5 +11,13 @@ enum Aligned { fn main() { let aligned = Aligned::Zero; let fo = aligned as u8; - println!("foo {}",fo); + println!("foo {}", fo); + println!("{}", tou8(Aligned::Zero)); +} + +#[inline(never)] +fn tou8(al: Aligned) -> u8 { + // Cast behind a function call so ConstProp does not see it + // (so that we can test codegen). + al as u8 } diff --git a/src/test/ui/layout/issue-96185-overaligned-enum.rs b/src/test/ui/layout/issue-96185-overaligned-enum.rs new file mode 100644 index 0000000000000..ae1e6b012c39b --- /dev/null +++ b/src/test/ui/layout/issue-96185-overaligned-enum.rs @@ -0,0 +1,19 @@ +// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +// This cannot use `Scalar` abi since there is padding. +#[rustc_layout(debug)] +#[repr(align(8))] +pub enum Aligned1 { //~ ERROR: layout_of + Zero = 0, + One = 1, +} + +// This should use `Scalar` abi. +#[rustc_layout(debug)] +#[repr(align(1))] +pub enum Aligned2 { //~ ERROR: layout_of + Zero = 0, + One = 1, +} diff --git a/src/test/ui/layout/issue-96185-overaligned-enum.stderr b/src/test/ui/layout/issue-96185-overaligned-enum.stderr new file mode 100644 index 0000000000000..8dc364fa7c9bd --- /dev/null +++ b/src/test/ui/layout/issue-96185-overaligned-enum.stderr @@ -0,0 +1,172 @@ +error: layout_of(Aligned1) = Layout { + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $PREF_ALIGN, + }, + size: Size(8 bytes), + }, + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 1, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $PREF_ALIGN, + }, + size: Size(8 bytes), + }, + ], + }, + abi: Aggregate { + sized: true, + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $PREF_ALIGN, + }, + size: Size(8 bytes), + } + --> $DIR/issue-96185-overaligned-enum.rs:8:1 + | +LL | pub enum Aligned1 { + | ^^^^^^^^^^^^^^^^^ + +error: layout_of(Aligned2) = Layout { + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $PREF_ALIGN, + }, + size: Size(1 bytes), + }, + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 1, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $PREF_ALIGN, + }, + size: Size(1 bytes), + }, + ], + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $PREF_ALIGN, + }, + size: Size(1 bytes), + } + --> $DIR/issue-96185-overaligned-enum.rs:16:1 + | +LL | pub enum Aligned2 { + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From d5721ce3a0f0d8eb2c46d87440b1977b5aef972c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 13:26:52 -0400 Subject: [PATCH 2/2] add asserts --- src/test/ui/aligned_enum_cast.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/ui/aligned_enum_cast.rs b/src/test/ui/aligned_enum_cast.rs index 7fbfc760d09c8..1ddf127172e65 100644 --- a/src/test/ui/aligned_enum_cast.rs +++ b/src/test/ui/aligned_enum_cast.rs @@ -12,7 +12,9 @@ fn main() { let aligned = Aligned::Zero; let fo = aligned as u8; println!("foo {}", fo); + assert_eq!(fo, 0); println!("{}", tou8(Aligned::Zero)); + assert_eq!(tou8(Aligned::Zero), 0); } #[inline(never)]