about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-08-23 18:22:38 +0200
committerSamuel Tardieu <sam@rfc1149.net>2025-08-23 19:25:58 +0200
commit323e23005a6a2025508e6064a0f88dae09cfa127 (patch)
tree29a08086269672d21f1436c1a4d7357da229de00
parent6d6a08cf590ec26296447b8d2cf2329bb64c303a (diff)
downloadrust-323e23005a6a2025508e6064a0f88dae09cfa127.tar.gz
rust-323e23005a6a2025508e6064a0f88dae09cfa127.zip
Fix ICE when validating transmuting ZST to inhabited enum
MIR validation attempts to determine the number of bytes needed to
represent the size of the source type to compute the discriminant for
the inhabited target enum. For a ZST source, there is no source data to
use as a discriminant so no proper runtime check can be generated.

Since that should never be possible, insert a delayed bug to ensure the
problem has been properly reported to the user by the type checker.
-rw-r--r--compiler/rustc_mir_transform/src/check_enums.rs15
-rw-r--r--tests/ui/mir/validate/ice-zst-as-discr-145786.rs14
-rw-r--r--tests/ui/mir/validate/ice-zst-as-discr-145786.stderr12
3 files changed, 41 insertions, 0 deletions
diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs
index 33a87cb9873..12447dc7cbb 100644
--- a/compiler/rustc_mir_transform/src/check_enums.rs
+++ b/compiler/rustc_mir_transform/src/check_enums.rs
@@ -48,6 +48,21 @@ impl<'tcx> crate::MirPass<'tcx> for CheckEnums {
                     let new_block = split_block(basic_blocks, location);
 
                     match check {
+                        EnumCheckType::Direct { op_size, .. }
+                        | EnumCheckType::WithNiche { op_size, .. }
+                            if op_size.bytes() == 0 =>
+                        {
+                            // It is never valid to use a ZST as a discriminant for an inhabited enum, but that will
+                            // have been caught by the type checker. Do nothing but ensure that a bug has been signaled.
+                            tcx.dcx().span_delayed_bug(
+                                source_info.span,
+                                "cannot build enum discriminant from zero-sized type",
+                            );
+                            basic_blocks[block].terminator = Some(Terminator {
+                                source_info,
+                                kind: TerminatorKind::Goto { target: new_block },
+                            });
+                        }
                         EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => {
                             insert_direct_enum_check(
                                 tcx,
diff --git a/tests/ui/mir/validate/ice-zst-as-discr-145786.rs b/tests/ui/mir/validate/ice-zst-as-discr-145786.rs
new file mode 100644
index 00000000000..616736bcf12
--- /dev/null
+++ b/tests/ui/mir/validate/ice-zst-as-discr-145786.rs
@@ -0,0 +1,14 @@
+// Do not attempt to take the discriminant as the source
+// converted to a `u128`, that won't work for ZST.
+//
+//@ compile-flags: -Zvalidate-mir
+
+enum A {
+    B,
+    C,
+}
+
+fn main() {
+    let _: A = unsafe { std::mem::transmute(()) };
+    //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
+}
diff --git a/tests/ui/mir/validate/ice-zst-as-discr-145786.stderr b/tests/ui/mir/validate/ice-zst-as-discr-145786.stderr
new file mode 100644
index 00000000000..b0bca1eb39c
--- /dev/null
+++ b/tests/ui/mir/validate/ice-zst-as-discr-145786.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/ice-zst-as-discr-145786.rs:12:25
+   |
+LL |     let _: A = unsafe { std::mem::transmute(()) };
+   |                         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `()` (0 bits)
+   = note: target type: `A` (8 bits)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0512`.