summaryrefslogtreecommitdiffstats
path: root/tests/ui/layout
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/layout')
-rw-r--r--tests/ui/layout/big-type-no-err.rs13
-rw-r--r--tests/ui/layout/debug.rs22
-rw-r--r--tests/ui/layout/debug.stderr311
-rw-r--r--tests/ui/layout/hexagon-enum.rs34
-rw-r--r--tests/ui/layout/hexagon-enum.stderr352
-rw-r--r--tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs36
-rw-r--r--tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr14
-rw-r--r--tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs72
-rw-r--r--tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr32
-rw-r--r--tests/ui/layout/issue-60431-unsized-tail-behind-projection.rs35
-rw-r--r--tests/ui/layout/issue-84108.rs14
-rw-r--r--tests/ui/layout/issue-84108.stderr44
-rw-r--r--tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs54
-rw-r--r--tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr655
-rw-r--r--tests/ui/layout/issue-96185-overaligned-enum.rs19
-rw-r--r--tests/ui/layout/issue-96185-overaligned-enum.stderr172
-rw-r--r--tests/ui/layout/thin-meta-implies-thin-ptr.rs11
-rw-r--r--tests/ui/layout/thumb-enum.rs34
-rw-r--r--tests/ui/layout/thumb-enum.stderr352
-rw-r--r--tests/ui/layout/unsafe-cell-hides-niche.rs82
-rw-r--r--tests/ui/layout/valid_range_oob.rs15
-rw-r--r--tests/ui/layout/valid_range_oob.stderr6
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.rs45
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.stderr424
-rw-r--r--tests/ui/layout/zero-sized-array-union.rs95
-rw-r--r--tests/ui/layout/zero-sized-array-union.stderr26
26 files changed, 2969 insertions, 0 deletions
diff --git a/tests/ui/layout/big-type-no-err.rs b/tests/ui/layout/big-type-no-err.rs
new file mode 100644
index 000000000..af8191a9c
--- /dev/null
+++ b/tests/ui/layout/big-type-no-err.rs
@@ -0,0 +1,13 @@
+// Enormous types are allowed if they are never actually instantiated.
+// run-pass
+trait Foo {
+ type Assoc;
+}
+
+impl Foo for [u16; usize::MAX] {
+ type Assoc = u32;
+}
+
+fn main() {
+ let _a: Option<<[u16; usize::MAX] as Foo>::Assoc> = None;
+}
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
new file mode 100644
index 000000000..a282e7123
--- /dev/null
+++ b/tests/ui/layout/debug.rs
@@ -0,0 +1,22 @@
+// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+#![feature(never_type, rustc_attrs, type_alias_impl_trait)]
+#![crate_type = "lib"]
+
+#[rustc_layout(debug)]
+enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+type Test = Result<i32, i32>; //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+type T = impl std::fmt::Debug; //~ ERROR: layout_of
+
+fn f() -> T {
+ 0i32
+}
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
new file mode 100644
index 000000000..c5e1c41d1
--- /dev/null
+++ b/tests/ui/layout/debug.stderr
@@ -0,0 +1,311 @@
+error: layout_of(E) = Layout {
+ size: Size(12 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_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..=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(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(12 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Uninhabited,
+ fields: Arbitrary {
+ offsets: [
+ Size(4 bytes),
+ Size(4 bytes),
+ Size(8 bytes),
+ ],
+ memory_index: [
+ 0,
+ 1,
+ 2,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/debug.rs:6:1
+ |
+LL | enum E { Foo, Bar(!, i32, i32) }
+ | ^^^^^^
+
+error: layout_of(S) = Layout {
+ size: Size(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ Size(0 bytes),
+ Size(4 bytes),
+ ],
+ memory_index: [
+ 1,
+ 0,
+ 2,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ }
+ --> $DIR/debug.rs:9:1
+ |
+LL | struct S { f1: i32, f2: (), f3: i32 }
+ | ^^^^^^^^
+
+error: layout_of(U) = Layout {
+ size: Size(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Union(
+ 2,
+ ),
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ }
+ --> $DIR/debug.rs:12:1
+ |
+LL | union U { f1: (i32, i32), f3: i32 }
+ | ^^^^^^^
+
+error: layout_of(std::result::Result<i32, i32>) = Layout {
+ size: Size(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
+ 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(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(4 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(4 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/debug.rs:15:1
+ |
+LL | type Test = Result<i32, i32>;
+ | ^^^^^^^^^
+
+error: layout_of(i32) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ }
+ --> $DIR/debug.rs:18:1
+ |
+LL | type T = impl std::fmt::Debug;
+ | ^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/hexagon-enum.rs b/tests/ui/layout/hexagon-enum.rs
new file mode 100644
index 000000000..4c58537e3
--- /dev/null
+++ b/tests/ui/layout/hexagon-enum.rs
@@ -0,0 +1,34 @@
+// compile-flags: --target hexagon-unknown-linux-musl
+// needs-llvm-components: hexagon
+//
+// Verify that the hexagon targets implement the repr(C) for enums correctly.
+//
+// See #82100
+#![feature(never_type, rustc_attrs, no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum A { Apple } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum B { Banana = 255, } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum C { Chaenomeles = 256, } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
+
+const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr
new file mode 100644
index 000000000..d850dd69c
--- /dev/null
+++ b/tests/ui/layout/hexagon-enum.stderr
@@ -0,0 +1,352 @@
+error: layout_of(A) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: Align(1 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=0,
+ },
+ ),
+ 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: Align(1 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/hexagon-enum.rs:16:1
+ |
+LL | enum A { Apple }
+ | ^^^^^^
+
+error: layout_of(B) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: Align(1 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 255..=255,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 255..=255,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 255..=255,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: Align(1 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/hexagon-enum.rs:20:1
+ |
+LL | enum B { Banana = 255, }
+ | ^^^^^^
+
+error: layout_of(C) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(2 bytes),
+ pref: Align(2 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 256..=256,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 256..=256,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 256..=256,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(2 bytes),
+ pref: Align(2 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/hexagon-enum.rs:24:1
+ |
+LL | enum C { Chaenomeles = 256, }
+ | ^^^^^^
+
+error: layout_of(P) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 268435456..=268435456,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 268435456..=268435456,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 268435456..=268435456,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/hexagon-enum.rs:28:1
+ |
+LL | enum P { Peach = 0x1000_0000isize, }
+ | ^^^^^^
+
+error: layout_of(T) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 2164260864..=2164260864,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 2164260864..=2164260864,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 2164260864..=2164260864,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/hexagon-enum.rs:34:1
+ |
+LL | enum T { Tangerine = TANGERINE as isize }
+ | ^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
new file mode 100644
index 000000000..7eecd99dc
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
@@ -0,0 +1,36 @@
+#![feature(rustc_attrs)]
+
+// Show that `homogeneous_aggregate` code ignores zero-length C
+// arrays. This matches the recent C standard, though not the
+// behavior of all older compilers, which sometimes consider `T[0]` to
+// be a "flexible array member" (see discussion on #56877 for
+// details).
+
+#[repr(C)]
+pub struct Foo {
+ x: u32
+}
+
+#[repr(C)]
+pub struct Middle {
+ pub a: f32,
+ pub foo: [Foo; 0],
+ pub b: f32,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type TestMiddle = Middle;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous
+
+#[repr(C)]
+pub struct Final {
+ pub a: f32,
+ pub b: f32,
+ pub foo: [Foo; 0],
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type TestFinal = Final;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous
+
+fn main() { }
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr
new file mode 100644
index 000000000..e19216a99
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr
@@ -0,0 +1,14 @@
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:22:1
+ |
+LL | pub type TestMiddle = Middle;
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:33:1
+ |
+LL | pub type TestFinal = Final;
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
new file mode 100644
index 000000000..a473c5c97
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
@@ -0,0 +1,72 @@
+#![feature(rustc_attrs)]
+
+// Regression test for #56877. We want to ensure that the presence of
+// `PhantomData` does not prevent `Bar` from being considered a
+// homogeneous aggregate.
+
+#[repr(C)]
+pub struct BaseCase {
+ pub a: f32,
+ pub b: f32,
+}
+
+#[repr(C)]
+pub struct WithPhantomData {
+ pub a: f32,
+ pub b: f32,
+ pub _unit: std::marker::PhantomData<()>,
+}
+
+pub struct EmptyRustStruct {}
+
+#[repr(C)]
+pub struct WithEmptyRustStruct {
+ pub a: f32,
+ pub b: f32,
+ pub _unit: EmptyRustStruct,
+}
+
+pub struct TransitivelyEmptyRustStruct {
+ field: EmptyRustStruct,
+ array: [u32; 0],
+}
+
+#[repr(C)]
+pub struct WithTransitivelyEmptyRustStruct {
+ pub a: f32,
+ pub b: f32,
+ pub _unit: TransitivelyEmptyRustStruct,
+}
+
+pub enum EmptyRustEnum {
+ Dummy,
+}
+
+#[repr(C)]
+pub struct WithEmptyRustEnum {
+ pub a: f32,
+ pub b: f32,
+ pub _unit: EmptyRustEnum,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test1 = BaseCase;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test2 = WithPhantomData;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test3 = WithEmptyRustStruct;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test4 = WithTransitivelyEmptyRustStruct;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test5 = WithEmptyRustEnum;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+fn main() {}
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr
new file mode 100644
index 000000000..17d639da0
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr
@@ -0,0 +1,32 @@
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:53:1
+ |
+LL | pub type Test1 = BaseCase;
+ | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:57:1
+ |
+LL | pub type Test2 = WithPhantomData;
+ | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:61:1
+ |
+LL | pub type Test3 = WithEmptyRustStruct;
+ | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:65:1
+ |
+LL | pub type Test4 = WithTransitivelyEmptyRustStruct;
+ | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:69:1
+ |
+LL | pub type Test5 = WithEmptyRustEnum;
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/issue-60431-unsized-tail-behind-projection.rs b/tests/ui/layout/issue-60431-unsized-tail-behind-projection.rs
new file mode 100644
index 000000000..65845d2c9
--- /dev/null
+++ b/tests/ui/layout/issue-60431-unsized-tail-behind-projection.rs
@@ -0,0 +1,35 @@
+// rust-lang/rust#60431: This is a scenario where to determine the size of
+// `&Ref<Obstack>`, we need to know the concrete type of the last field in
+// `Ref<Obstack>` (i.e. its "struct tail"), and determining that concrete type
+// requires normalizing `Obstack::Dyn`.
+//
+// The old "struct tail" computation did not perform such normalization, and so
+// the compiler would ICE when trying to figure out if `Ref<Obstack>` is a
+// dynamically-sized type (DST).
+
+// run-pass
+
+use std::mem;
+
+pub trait Arena {
+ type Dyn : ?Sized;
+}
+
+pub struct DynRef {
+ _dummy: [()],
+}
+
+pub struct Ref<A: Arena> {
+ _value: u8,
+ _dyn_arena: A::Dyn,
+}
+
+pub struct Obstack;
+
+impl Arena for Obstack {
+ type Dyn = DynRef;
+}
+
+fn main() {
+ assert_eq!(mem::size_of::<&Ref<Obstack>>(), mem::size_of::<&[()]>());
+}
diff --git a/tests/ui/layout/issue-84108.rs b/tests/ui/layout/issue-84108.rs
new file mode 100644
index 000000000..dd025c9b4
--- /dev/null
+++ b/tests/ui/layout/issue-84108.rs
@@ -0,0 +1,14 @@
+// See issue #84108 -- this is a test to ensure we do not ICE
+// on this invalid code.
+
+#![crate_type = "lib"]
+
+static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+//~^ ERROR cannot find type `OsStr` in this scope
+
+const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+//~^ ERROR cannot find type `Path` in this scope
+//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+static BAZ: ([u8], usize) = ([], 0);
+//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr
new file mode 100644
index 000000000..36be64241
--- /dev/null
+++ b/tests/ui/layout/issue-84108.stderr
@@ -0,0 +1,44 @@
+error[E0412]: cannot find type `OsStr` in this scope
+ --> $DIR/issue-84108.rs:6:24
+ |
+LL | static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+ | ^^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL | use std::ffi::OsStr;
+ |
+
+error[E0412]: cannot find type `Path` in this scope
+ --> $DIR/issue-84108.rs:9:14
+ |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+ | ^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL | use std::path::Path;
+ |
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-84108.rs:9:12
+ |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+ | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-84108.rs:13:13
+ |
+LL | static BAZ: ([u8], usize) = ([], 0);
+ | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0412.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
new file mode 100644
index 000000000..af5f5885d
--- /dev/null
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
@@ -0,0 +1,54 @@
+// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+use std::mem::MaybeUninit;
+
+enum HasNiche {
+ A,
+ B,
+ C,
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since the u8 payload will be uninit for `None`.
+#[rustc_layout(debug)]
+pub enum MissingPayloadField { //~ ERROR: layout_of
+ Some(u8),
+ None
+}
+
+// This should result in ScalarPair(Initialized, Initialized),
+// since the u8 field is present in all variants,
+// and hence will always be initialized.
+#[rustc_layout(debug)]
+pub enum CommonPayloadField { //~ ERROR: layout_of
+ A(u8),
+ B(u8),
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since, though a u8-sized field is present in all variants, it might be uninit.
+#[rustc_layout(debug)]
+pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
+ A(u8),
+ B(MaybeUninit<u8>),
+}
+
+// This should result in ScalarPair(Initialized, Union),
+// since only the niche field (used for the tag) is guaranteed to be initialized.
+#[rustc_layout(debug)]
+pub enum NicheFirst { //~ ERROR: layout_of
+ A(HasNiche, u8),
+ B,
+ C
+}
+
+// This should result in ScalarPair(Union, Initialized),
+// since only the niche field (used for the tag) is guaranteed to be initialized.
+#[rustc_layout(debug)]
+pub enum NicheSecond { //~ ERROR: layout_of
+ A(u8, HasNiche),
+ B,
+ C,
+}
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
new file mode 100644
index 000000000..20d4c418e
--- /dev/null
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
@@ -0,0 +1,655 @@
+error: layout_of(MissingPayloadField) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_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(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_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: 0,
+ },
+ },
+ Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1
+ |
+LL | pub enum MissingPayloadField {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(CommonPayloadField) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ 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(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1
+ |
+LL | pub enum CommonPayloadField {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_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(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_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: 0,
+ },
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_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,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1
+ |
+LL | pub enum CommonPayloadFieldIsMaybeUninit {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(NicheFirst) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ tag_encoding: Niche {
+ untagged_variant: 0,
+ niche_variants: 1..=2,
+ niche_start: 3,
+ },
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 1,
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 2,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1
+ |
+LL | pub enum NicheFirst {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(NicheSecond) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=4,
+ },
+ tag_encoding: Niche {
+ untagged_variant: 0,
+ niche_variants: 1..=2,
+ niche_start: 3,
+ },
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ 1,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ ),
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 2,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1
+ |
+LL | pub enum NicheSecond {
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/issue-96185-overaligned-enum.rs b/tests/ui/layout/issue-96185-overaligned-enum.rs
new file mode 100644
index 000000000..ae1e6b012
--- /dev/null
+++ b/tests/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/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr
new file mode 100644
index 000000000..de6177c8d
--- /dev/null
+++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr
@@ -0,0 +1,172 @@
+error: layout_of(Aligned1) = Layout {
+ size: Size(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(8 bytes),
+ pref: $PREF_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(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(8 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(8 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(8 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96185-overaligned-enum.rs:8:1
+ |
+LL | pub enum Aligned1 {
+ | ^^^^^^^^^^^^^^^^^
+
+error: layout_of(Aligned2) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ 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: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/issue-96185-overaligned-enum.rs:16:1
+ |
+LL | pub enum Aligned2 {
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/layout/thin-meta-implies-thin-ptr.rs b/tests/ui/layout/thin-meta-implies-thin-ptr.rs
new file mode 100644
index 000000000..972579ea8
--- /dev/null
+++ b/tests/ui/layout/thin-meta-implies-thin-ptr.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(ptr_metadata)]
+
+use std::ptr::Thin;
+
+fn main() {}
+
+fn foo<T: ?Sized + Thin>(t: *const T) -> *const () {
+ unsafe { std::mem::transmute(t) }
+}
diff --git a/tests/ui/layout/thumb-enum.rs b/tests/ui/layout/thumb-enum.rs
new file mode 100644
index 000000000..3b43b1b83
--- /dev/null
+++ b/tests/ui/layout/thumb-enum.rs
@@ -0,0 +1,34 @@
+// compile-flags: --target thumbv8m.main-none-eabihf
+// needs-llvm-components: arm
+//
+// Verify that thumb targets implement the repr(C) for enums correctly.
+//
+// See #87917
+#![feature(never_type, rustc_attrs, no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum A { Apple } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum B { Banana = 255, } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum C { Chaenomeles = 256, } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
+
+const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr
new file mode 100644
index 000000000..227bd950b
--- /dev/null
+++ b/tests/ui/layout/thumb-enum.stderr
@@ -0,0 +1,352 @@
+error: layout_of(A) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=0,
+ },
+ ),
+ 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: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/thumb-enum.rs:16:1
+ |
+LL | enum A { Apple }
+ | ^^^^^^
+
+error: layout_of(B) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 255..=255,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 255..=255,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 255..=255,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/thumb-enum.rs:20:1
+ |
+LL | enum B { Banana = 255, }
+ | ^^^^^^
+
+error: layout_of(C) = Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(2 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 256..=256,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 256..=256,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 256..=256,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(2 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/thumb-enum.rs:24:1
+ |
+LL | enum C { Chaenomeles = 256, }
+ | ^^^^^^
+
+error: layout_of(P) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 268435456..=268435456,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 268435456..=268435456,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 268435456..=268435456,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/thumb-enum.rs:28:1
+ |
+LL | enum P { Peach = 0x1000_0000isize, }
+ | ^^^^^^
+
+error: layout_of(T) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Scalar(
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 2164260864..=2164260864,
+ },
+ ),
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 2164260864..=2164260864,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 2164260864..=2164260864,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: Align(4 bytes),
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [],
+ memory_index: [],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/thumb-enum.rs:34:1
+ |
+LL | enum T { Tangerine = TANGERINE as isize }
+ | ^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/layout/unsafe-cell-hides-niche.rs b/tests/ui/layout/unsafe-cell-hides-niche.rs
new file mode 100644
index 000000000..68bcc3c1a
--- /dev/null
+++ b/tests/ui/layout/unsafe-cell-hides-niche.rs
@@ -0,0 +1,82 @@
+// For rust-lang/rust#68303: the contents of `UnsafeCell<T>` cannot
+// participate in the niche-optimization for enum discriminants. This
+// test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same
+// size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes).
+
+// check-pass
+// compile-flags: --crate-type=lib
+// only-x86
+
+#![feature(repr_simd)]
+
+use std::cell::{UnsafeCell, RefCell, Cell};
+use std::mem::size_of;
+use std::num::NonZeroU32 as N32;
+use std::sync::{Mutex, RwLock};
+
+struct Wrapper<T>(#[allow(unused_tuple_struct_fields)] T);
+
+#[repr(transparent)]
+struct Transparent<T>(#[allow(unused_tuple_struct_fields)] T);
+
+struct NoNiche<T>(UnsafeCell<T>);
+
+struct Size<const S: usize>;
+
+macro_rules! check_sizes {
+ (check_one_specific_size: $ty:ty, $size:expr) => {
+ const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>;
+ };
+ // Any tests run on `UnsafeCell` must be the same for `Cell`
+ (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => {
+ check_sizes!(Cell<$ty>: $size => $optioned_size);
+ check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size);
+ };
+ ($ty:ty: $size:expr => $optioned_size:expr) => {
+ check_sizes!(@actual_check: $ty: $size => $optioned_size);
+ };
+ // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish
+ // it from other branches and not accidentally match any.
+ (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => {
+ check_sizes!(check_one_specific_size: $ty, $size);
+ check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size);
+ check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty);
+ };
+ // only check that there is no niche (size goes up when wrapped in an option),
+ // don't check actual sizes
+ ($ty:ty) => {
+ check_sizes!(check_no_niche_opt: true, $ty);
+ };
+ (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => {
+ const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::<Option<$ty>>()); };
+ };
+}
+
+const PTR_SIZE: usize = std::mem::size_of::<*const ()>();
+
+check_sizes!(Wrapper<u32>: 4 => 8);
+check_sizes!(Wrapper<N32>: 4 => 4); // (✓ niche opt)
+check_sizes!(Transparent<u32>: 4 => 8);
+check_sizes!(Transparent<N32>: 4 => 4); // (✓ niche opt)
+check_sizes!(NoNiche<u32>: 4 => 8);
+check_sizes!(NoNiche<N32>: 4 => 8);
+
+check_sizes!(UnsafeCell<u32>: 4 => 8);
+check_sizes!(UnsafeCell<N32>: 4 => 8);
+
+check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2);
+check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+check_sizes!(RwLock<&()>);
+check_sizes!(Mutex<&()>);
+
+check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3);
+check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+trait Trait {}
+check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+#[repr(simd)]
+pub struct Vec4<T>([T; 4]);
+
+check_sizes!(UnsafeCell<Vec4<N32>>: 16 => 32);
diff --git a/tests/ui/layout/valid_range_oob.rs b/tests/ui/layout/valid_range_oob.rs
new file mode 100644
index 000000000..74aa47fe4
--- /dev/null
+++ b/tests/ui/layout/valid_range_oob.rs
@@ -0,0 +1,15 @@
+// failure-status: 101
+// normalize-stderr-test "note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// rustc-env:RUST_BACKTRACE=0
+
+#![feature(rustc_attrs)]
+
+#[rustc_layout_scalar_valid_range_end(257)]
+struct Foo(i8);
+
+// Need to do in a constant, as runtime codegen
+// does not compute the layout of `Foo` in check builds.
+const FOO: Foo = unsafe { Foo(1) };
+
+fn main() {}
diff --git a/tests/ui/layout/valid_range_oob.stderr b/tests/ui/layout/valid_range_oob.stderr
new file mode 100644
index 000000000..7398f0164
--- /dev/null
+++ b/tests/ui/layout/valid_range_oob.stderr
@@ -0,0 +1,6 @@
+error: internal compiler error: unexpected panic
+
+query stack during panic:
+#0 [layout_of] computing layout of `Foo`
+#1 [eval_to_allocation_raw] const-evaluating + checking `FOO`
+end of query stack
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs
new file mode 100644
index 000000000..23bbbfbfc
--- /dev/null
+++ b/tests/ui/layout/zero-sized-array-enum-niche.rs
@@ -0,0 +1,45 @@
+// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+#![feature(rustc_attrs)]
+#![crate_type = "lib"]
+
+// Various tests around the behavior of zero-sized arrays and
+// enum niches, especially that they have coherent size and alignment.
+
+// The original problem in #99836 came from ndarray's `TryFrom` for
+// `SliceInfo<[SliceInfoElem; 0], Din, Dout>`, where that returns
+// `Result<Self, ShapeError>` ~= `Result<AlignedZST, TypeWithNiche>`.
+// This is a close enough approximation:
+#[rustc_layout(debug)]
+type AlignedResult = Result<[u32; 0], bool>; //~ ERROR: layout_of
+// The bug gave that size 1 with align 4, but the size should also be 4.
+// It was also using the bool niche for the enum tag, which is fine, but
+// after the fix, layout decides to use a direct tagged repr instead.
+
+// Here's another case with multiple ZST alignments, where we should
+// get the maximal alignment and matching size.
+#[rustc_layout(debug)]
+enum MultipleAlignments { //~ ERROR: layout_of
+ Align2([u16; 0]),
+ Align4([u32; 0]),
+ Niche(bool),
+}
+
+// Tagged repr is clever enough to grow tags to fill any padding, e.g.:
+// 1. `T_FF` (one byte of Tag, one byte of padding, two bytes of align=2 Field)
+// -> `TTFF` (Tag has expanded to two bytes, i.e. like `#[repr(u16)]`)
+// 2. `TFF` (one byte of Tag, two bytes of align=1 Field)
+// -> Tag has no room to expand!
+// (this outcome can be forced onto 1. by wrapping Field in `Packed<...>`)
+#[repr(packed)]
+struct Packed<T>(T);
+
+#[rustc_layout(debug)]
+type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZeroU16>>; //~ ERROR: layout_of
+// Should get tag_encoding: Direct, size == align == 4.
+
+#[repr(u16)]
+enum U16IsZero { _Zero = 0 }
+
+#[rustc_layout(debug)]
+type NicheWinsOverTagged = Result<[u32; 0], Packed<U16IsZero>>; //~ ERROR: layout_of
+// Should get tag_encoding: Niche, size == align == 4.
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr
new file mode 100644
index 000000000..a3e82070e
--- /dev/null
+++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr
@@ -0,0 +1,424 @@
+error: layout_of(std::result::Result<[u32; 0], bool>) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_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(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(4 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/zero-sized-array-enum-niche.rs:13:1
+ |
+LL | type AlignedResult = Result<[u32; 0], bool>;
+ | ^^^^^^^^^^^^^^^^^^
+
+error: layout_of(MultipleAlignments) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_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..=2,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=2,
+ },
+ tag_encoding: Direct,
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(2 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(2 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(4 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 1,
+ },
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ variants: Single {
+ index: 2,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/zero-sized-array-enum-niche.rs:21:1
+ |
+LL | enum MultipleAlignments {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_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(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(4 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(3 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(1 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(1 bytes),
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 1..=65535,
+ },
+ ),
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/zero-sized-array-enum-niche.rs:37:1
+ |
+LL | type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZeroU16>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
+ size: Size(4 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ ),
+ variants: Multiple {
+ tag: Initialized {
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ tag_encoding: Niche {
+ untagged_variant: 1,
+ niche_variants: 0..=0,
+ niche_start: 1,
+ },
+ tag_field: 0,
+ variants: [
+ Layout {
+ size: Size(0 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(4 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: None,
+ variants: Single {
+ index: 0,
+ },
+ },
+ Layout {
+ size: Size(2 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $PREF_ALIGN,
+ },
+ abi: Aggregate {
+ sized: true,
+ },
+ fields: Arbitrary {
+ offsets: [
+ Size(0 bytes),
+ ],
+ memory_index: [
+ 0,
+ ],
+ },
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I16,
+ false,
+ ),
+ valid_range: 0..=0,
+ },
+ ),
+ variants: Single {
+ index: 1,
+ },
+ },
+ ],
+ },
+ }
+ --> $DIR/zero-sized-array-enum-niche.rs:44:1
+ |
+LL | type NicheWinsOverTagged = Result<[u32; 0], Packed<U16IsZero>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/layout/zero-sized-array-union.rs b/tests/ui/layout/zero-sized-array-union.rs
new file mode 100644
index 000000000..1a662ba44
--- /dev/null
+++ b/tests/ui/layout/zero-sized-array-union.rs
@@ -0,0 +1,95 @@
+#![feature(rustc_attrs)]
+
+// Various tests around the behavior of zero-sized arrays and
+// unions. This matches the behavior of modern C compilers, though
+// older compilers (and sometimes clang) treat `T[0]` as a "flexible
+// array member". See more
+// details in #56877.
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct Empty { }
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct Empty2 {
+ e: Empty
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct Empty3 {
+ z: [f32; 0],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct Empty4 {
+ e: Empty3
+}
+
+#[repr(C)]
+union U1 {
+ s: Empty
+}
+
+#[repr(C)]
+union U2 {
+ s: Empty2
+}
+
+#[repr(C)]
+union U3 {
+ s: Empty3
+}
+
+#[repr(C)]
+union U4 {
+ s: Empty4
+}
+
+#[repr(C)]
+struct Baz1 {
+ x: f32,
+ y: f32,
+ u: U1,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+type TestBaz1 = Baz1;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous
+
+#[repr(C)]
+struct Baz2 {
+ x: f32,
+ y: f32,
+ u: U2,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+type TestBaz2 = Baz2;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous
+
+#[repr(C)]
+struct Baz3 {
+ x: f32,
+ y: f32,
+ u: U3,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+type TestBaz3 = Baz3;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous
+
+#[repr(C)]
+struct Baz4 {
+ x: f32,
+ y: f32,
+ u: U4,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+type TestBaz4 = Baz4;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous
+
+fn main() { }
diff --git a/tests/ui/layout/zero-sized-array-union.stderr b/tests/ui/layout/zero-sized-array-union.stderr
new file mode 100644
index 000000000..de2b863e4
--- /dev/null
+++ b/tests/ui/layout/zero-sized-array-union.stderr
@@ -0,0 +1,26 @@
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/zero-sized-array-union.rs:59:1
+ |
+LL | type TestBaz1 = Baz1;
+ | ^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/zero-sized-array-union.rs:70:1
+ |
+LL | type TestBaz2 = Baz2;
+ | ^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/zero-sized-array-union.rs:81:1
+ |
+LL | type TestBaz3 = Baz3;
+ | ^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+ --> $DIR/zero-sized-array-union.rs:92:1
+ |
+LL | type TestBaz4 = Baz4;
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+