about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGoldstein <root@goldstein.rs>2024-03-25 20:44:58 +0300
committerGoldstein <root@goldstein.rs>2024-06-28 20:19:45 +0300
commit71dfbeabc4abe992a42025a5b7341e1ceec22e0b (patch)
tree352b7a8b9aaf8ea6ceb2b9e228059421fdb238a1
parent1a851da73cdeb02e2c62d301aa6bd98e515a50da (diff)
downloadrust-71dfbeabc4abe992a42025a5b7341e1ceec22e0b.tar.gz
rust-71dfbeabc4abe992a42025a5b7341e1ceec22e0b.zip
Disable dead variant removal for `#[repr(C)]` enums.
See https://github.com/rust-lang/unsafe-code-guidelines/issues/500.
-rw-r--r--compiler/rustc_abi/src/layout.rs4
-rw-r--r--compiler/rustc_abi/src/lib.rs2
-rw-r--r--tests/ui/abi/compatibility.rs4
-rw-r--r--tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr288
-rw-r--r--tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr288
-rw-r--r--tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr288
-rw-r--r--tests/ui/repr/repr-c-dead-variants.rs63
-rw-r--r--tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr288
-rw-r--r--tests/ui/repr/repr-c-int-dead-variants.rs38
-rw-r--r--tests/ui/repr/repr-c-int-dead-variants.stderr288
10 files changed, 1548 insertions, 3 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index a95ef4c460f..aff0d70bf90 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -186,7 +186,7 @@ pub trait LayoutCalculator {
         let (present_first, present_second) = {
             let mut present_variants = variants
                 .iter_enumerated()
-                .filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
+                .filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) });
             (present_variants.next(), present_variants.next())
         };
         let present_first = match present_first {
@@ -621,7 +621,7 @@ where
     let discr_type = repr.discr_type();
     let bits = Integer::from_attr(dl, discr_type).size().bits();
     for (i, mut val) in discriminants {
-        if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
+        if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
             continue;
         }
         if discr_type.is_signed() {
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 5e3f64540e4..1e5e391d19b 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1401,7 +1401,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
 
-    /// Enum-likes with more than one inhabited variant: each variant comes with
+    /// Enum-likes with more than one variant: each variant comes with
     /// a *discriminant* (usually the same as the variant index but the user can
     /// assign explicit discriminant values). That discriminant is encoded
     /// as a *tag* on the machine. The layout of each variant is
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 373d1cce1d7..086177efb77 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -277,6 +277,10 @@ test_abi_compatible!(zst_unit, Zst, ());
 test_abi_compatible!(zst_array, Zst, [u8; 0]);
 test_abi_compatible!(nonzero_int, NonZero<i32>, i32);
 
+// `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness.
+enum Void {}
+test_abi_compatible!(repr_c_enum_void, ReprCEnum<Void>, ReprCEnum<ReprCUnion<Void>>);
+
 // `DispatchFromDyn` relies on ABI compatibility.
 // This is interesting since these types are not `repr(transparent)`. So this is not part of our
 // public ABI guarantees, but is relied on by the compiler.
diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
new file mode 100644
index 00000000000..e2e57fe0e73
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+                   Layout {
+                       size: Size(8 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
new file mode 100644
index 00000000000..6ecdab1cc14
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
new file mode 100644
index 00000000000..e2e57fe0e73
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+                   Layout {
+                       size: Size(8 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs
new file mode 100644
index 00000000000..f113588e83f
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.rs
@@ -0,0 +1,63 @@
+#![feature(no_core, rustc_attrs, lang_items)]
+#![allow(dead_code)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+// See also: repr-c-int-dead-variants.rs
+
+//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+
+// This test depends on the value of the `c_enum_min_bits` target option.
+// As there's no way to actually check it from UI test, we only run this test on a subset of archs.
+// Four archs specifically are chosen: one for major architectures (x86_64, i686, aarch64)
+// and `armebv7r-none-eabi` that has `c_enum_min_bits` set to 8.
+
+//@ revisions: aarch64-unknown-linux-gnu
+//@[aarch64-unknown-linux-gnu] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64-unknown-linux-gnu] needs-llvm-components: aarch64
+
+//@ revisions: i686-pc-windows-msvc
+//@[i686-pc-windows-msvc] compile-flags: --target i686-pc-windows-gnu
+//@[i686-pc-windows-msvc] needs-llvm-components: x86
+
+//@ revisions: x86_64-unknown-linux-gnu
+//@[x86_64-unknown-linux-gnu] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64-unknown-linux-gnu] needs-llvm-components: x86
+//
+//@ revisions: armebv7r-none-eabi
+//@[armebv7r-none-eabi] compile-flags: --target armebv7r-none-eabi
+//@[armebv7r-none-eabi] needs-llvm-components: arm
+
+// A simple uninhabited type.
+enum Void {}
+
+// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
+#[repr(C)]
+#[rustc_layout(debug)]
+enum Univariant { //~ ERROR layout_of
+    Variant(Void),
+}
+
+// ADTs with variants that have fields must have space allocated for those fields.
+#[repr(C)]
+#[rustc_layout(debug)]
+enum TwoVariants { //~ ERROR layout_of
+    Variant1(Void),
+    Variant2(u8),
+}
+
+// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned.
+#[repr(C, align(8))]
+struct Align8U64(u64);
+
+// This one is 2 x u64: we reserve space for fields in a dead branch.
+#[repr(C)]
+#[rustc_layout(debug)]
+enum DeadBranchHasOtherField { //~ ERROR layout_of
+    Variant1(Void, Align8U64),
+    Variant2(u8),
+}
+
+#[lang = "sized"]
+trait Sized {}
diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
new file mode 100644
index 00000000000..e2e57fe0e73
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+                   Layout {
+                       size: Size(8 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs
new file mode 100644
index 00000000000..8d2b39bd648
--- /dev/null
+++ b/tests/ui/repr/repr-c-int-dead-variants.rs
@@ -0,0 +1,38 @@
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+// See also: repr-c-dead-variants.rs
+
+//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+
+// A simple uninhabited type.
+enum Void {}
+
+// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
+#[repr(C, u8)]
+#[rustc_layout(debug)]
+enum UnivariantU8 { //~ ERROR layout_of
+    Variant(Void),
+}
+
+// ADTs with variants that have fields must have space allocated for those fields.
+#[repr(C, u8)]
+#[rustc_layout(debug)]
+enum TwoVariantsU8 { //~ ERROR layout_of
+    Variant1(Void),
+    Variant2(u8),
+}
+
+// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned.
+#[repr(C, align(8))]
+struct Align8U64(u64);
+
+// This one is 2 x u64: we reserve space for fields in a dead branch.
+#[repr(C, u8)]
+#[rustc_layout(debug)]
+enum DeadBranchHasOtherFieldU8 { //~ ERROR layout_of
+    Variant1(Void, Align8U64),
+    Variant2(u8),
+}
+
+fn main() {}
diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr
new file mode 100644
index 00000000000..f7df576df24
--- /dev/null
+++ b/tests/ui/repr/repr-c-int-dead-variants.stderr
@@ -0,0 +1,288 @@
+error: layout_of(UnivariantU8) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-int-dead-variants.rs:14:1
+   |
+LL | enum UnivariantU8 {
+   | ^^^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariantsU8) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-int-dead-variants.rs:21:1
+   |
+LL | enum TwoVariantsU8 {
+   | ^^^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-int-dead-variants.rs:33:1
+   |
+LL | enum DeadBranchHasOtherFieldU8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+