diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 11fd73c9094..8d9f2631897 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -345,11 +345,16 @@ pub fn compute( ty::Array(inner, len) if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts => { + let len_eval = len.try_eval_target_usize(tcx, param_env); + if len_eval == Some(0) { + return Ok(SizeSkeleton::Known(Size::from_bytes(0))); + } + match SizeSkeleton::compute(inner, tcx, param_env)? { // This may succeed because the multiplication of two types may overflow // but a single size of a nested array will not. SizeSkeleton::Known(s) => { - if let Some(c) = len.try_eval_target_usize(tcx, param_env) { + if let Some(c) = len_eval { let size = s .bytes() .checked_mul(c) diff --git a/tests/ui/transmute/transmute-zst-generics.rs b/tests/ui/transmute/transmute-zst-generics.rs new file mode 100644 index 00000000000..9aeb21923ea --- /dev/null +++ b/tests/ui/transmute/transmute-zst-generics.rs @@ -0,0 +1,34 @@ +//@ run-pass + +// Transmuting to/from ZSTs that contain generics. + +#![feature(transmute_generic_consts)] + +// Verify non-generic ZST -> generic ZST transmute +unsafe fn cast_zst0(from: ()) -> [T; 0] { + ::std::mem::transmute::<(), [T; 0]>(from) +} + +// Verify generic ZST -> non-generic ZST transmute +unsafe fn cast_zst1(from: [T; 0]) -> () { + ::std::mem::transmute::<[T; 0], ()>(from) +} + +// Verify transmute with generic compound types +unsafe fn cast_zst2(from: ()) -> [(T, T); 0] { + ::std::mem::transmute::<(), [(T, T); 0]>(from) +} + +// Verify transmute with ZST propagation through arrays +unsafe fn cast_zst3(from: ()) -> [[T; 0]; 8] { + ::std::mem::transmute::<(), [[T; 0]; 8]>(from) +} + +pub fn main() { + unsafe { + let _: [u32; 0] = cast_zst0(()); + let _ = cast_zst1::([]); + let _: [(u32, u32); 0] = cast_zst2(()); + let _: [[u32; 0]; 8] = cast_zst3(()); + }; +}