Skip to content

Commit

Permalink
Rollup merge of rust-lang#114009 - dvdhrm:pr/transmzst, r=pnkfelix
Browse files Browse the repository at this point in the history
compiler: allow transmute of ZST arrays with generics

Extend the `SizeSkeleton` evaluator to shortcut zero-sized arrays, thus considering `[T; 0]` to have a compile-time fixed-size of 0.

The existing evaluator already deals with generic arrays under the feature-guard `transmute_const_generics`. However, it merely allows comparing fixed-size types with fixed-size types, and generic types with generic types. For generic types, it merely compares whether their arguments match (ordering them first). Even if their exact sizes are not known at compile time, it can ensure that they will eventually be the same.

This patch extends this by shortcutting the size-evaluation of zero sized arrays and thus allowing size comparisons of `()` with `[T; 0]`, where one contains generics and the other does not.

This code is guarded by `transmute_const_generics` (rust-lang#109929), even though it is unclear whether it should be. However, this assumes that a separate stabilization PR is required to move this out of the feature guard.

Initially reported in rust-lang#98104.
  • Loading branch information
workingjubilee authored Mar 7, 2024
2 parents 07afa65 + 14be58a commit 0cd0ad6
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 1 deletion.
7 changes: 6 additions & 1 deletion compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,16 @@ impl<'tcx> SizeSkeleton<'tcx> {
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)
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/transmute/transmute-zst-generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// run-pass
// Transmuting to/from ZSTs that contain generics.

#![feature(transmute_generic_consts)]

unsafe fn cast_zst<T>(from: ()) -> [T; 0] {
::std::mem::transmute::<(), [T; 0]>(from)
}

pub fn main() {
unsafe {
let _: [u32; 0] = cast_zst(());
};
}

0 comments on commit 0cd0ad6

Please sign in to comment.