Compiler doesn't know that MaybeUninit<T> and T have the same size

I was attempting to use this function in a macro:

unsafe fn transmute_uninit_arr<T>(arr: [MaybeUninit<T>; #len]) -> [T; #len] {
    std::mem::transmute(arr)
}

I need it because I don't know the element type of the array that I'm initializing, so I can't name it explicitly. If I just return transmute::<_, [_; len]>() from my macro then a caller could accidentally provide a different type and the transmute would be unsound. The purpose of the function is to constrain the types so that an incorrect type cannot be inferred in arbitrary calls to the macro.

But I get an error:

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   = note: source type: `[MaybeUninit<T>; 4]` (size can vary because of T)
   = note: target type: `[T; 4]` (size can vary because of T)
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

It is my understanding that the size of MaybeUninit<T> is always the same as T, but it seems that this information cannot be used by the compiler in this situation.

How can I get around this?

This Reddit thread covered the same issue.

I think this is related to https://github.com/rust-lang/rust/issues/47966.

For now, you can work around this by using transmute_copy or raw pointer casts.

2 Likes

Thanks, I can make it work with pointer casts.

To "fix" transmute, I guess that would require something like a HasSize<const Size: usize> implemented for all sized types, so that transmute can bound its parameters on it. Are there RFCs like that? (Edit: found it)