diff options
| author | Samuel Tardieu <sam@rfc1149.net> | 2025-08-23 18:22:38 +0200 |
|---|---|---|
| committer | Samuel Tardieu <sam@rfc1149.net> | 2025-08-23 19:25:58 +0200 |
| commit | 323e23005a6a2025508e6064a0f88dae09cfa127 (patch) | |
| tree | 29a08086269672d21f1436c1a4d7357da229de00 | |
| parent | 6d6a08cf590ec26296447b8d2cf2329bb64c303a (diff) | |
| download | rust-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.rs | 15 | ||||
| -rw-r--r-- | tests/ui/mir/validate/ice-zst-as-discr-145786.rs | 14 | ||||
| -rw-r--r-- | tests/ui/mir/validate/ice-zst-as-discr-145786.stderr | 12 |
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`. |
