about summary refs log tree commit diff
path: root/tests/ui/layout
diff options
context:
space:
mode:
authorAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-05 09:13:28 +0100
committerAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-11 09:32:08 +0000
commitcf2dff2b1e3fa55fa5415d524200070d0d7aacfe (patch)
tree40a88d9a46aaf3e8870676eb2538378b75a263eb /tests/ui/layout
parentca855e6e42787ecd062d81d53336fe6788ef51a9 (diff)
downloadrust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.tar.gz
rust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.zip
Move /src/test to /tests
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 00000000000..af8191a9cb9
--- /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 00000000000..a282e71235c
--- /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 00000000000..c5e1c41d130
--- /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 00000000000..4c58537e309
--- /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 00000000000..d850dd69c96
--- /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 00000000000..7eecd99dc01
--- /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 00000000000..e19216a99db
--- /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 00000000000..a473c5c97c0
--- /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 00000000000..17d639da024
--- /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 00000000000..65845d2c9fe
--- /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 00000000000..dd025c9b443
--- /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 00000000000..36be6424110
--- /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 00000000000..af5f5885d67
--- /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 00000000000..20d4c418e87
--- /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 00000000000..ae1e6b012c3
--- /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 00000000000..de6177c8dfc
--- /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 00000000000..972579ea8be
--- /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 00000000000..3b43b1b83fa
--- /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 00000000000..227bd950b66
--- /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 00000000000..68bcc3c1aff
--- /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 00000000000..74aa47fe405
--- /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 00000000000..7398f01643f
--- /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 00000000000..23bbbfbfc58
--- /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 00000000000..a3e82070e0f
--- /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 00000000000..1a662ba4467
--- /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 00000000000..de2b863e4ca
--- /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
+