error[E0512]: cannot transmute between types of different sizes, or dependently-sized types

transmute 関数の入力型と出力型でサイズが一致していない。

背景

transmute 関数は型変換系のメソッドでビット列はそのままに型変換した事にする。

もちろんこの関数は unsafe である。また、他の unsafe な機能と比べても、誤用すると意味不明な挙動になりやすく、より危険である。そのため、なるべくこの関数を使わないで済むように stdcore では多くの実用的な変換がすでに用意されている。

そして、この関数は入力型と出力型のサイズが異なる場合、コンパイルエラーを発生させる (2025 年現在、Rust はユーザにはこうした型チェックを提供しないため、この関数は特別な扱いをされているようだ)。なお、この安全策すら取り払った transmute_copy もある。

パターン

パターン A

基本形

実際に入力型と出力型のサイズが異なるパターン。


use std::mem;

pub fn conv(src: [u32; 3]) -> [u8; 8] {
    unsafe { mem::transmute::<[u32; 3], [u8; 8]>([0, 0, 1]) }
}

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src\lib.rs:4:14
  |
4 |     unsafe { mem::transmute::<[u32; 3], [u8; 8]>([0, 0, 1]) }
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: source type: `[u32; 3]` (96 bits)
  = note: target type: `[u8; 8]` (64 bits)

パターン B1

PhantomData が関連するバグ

フィールドに PhantomData<T> と型パラメタを持つ型が混在すると発生する。

PhantomData<T> はダミーである。そのため、本来なら T が何であれサイズに関係ないはずである。しかし、なぜかこれを含むとサイズについて指摘されてしまう。

サンプル


use std::{marker::PhantomData, mem};

pub fn conv<T: Sized, U1, U2>(src: MyType<T, U1>) -> MyType<T, U2> {
    unsafe { mem::transmute::<MyType<T, U1>, MyType<T, U2>>(src) }
}

#[repr(transparent)]
pub struct MyType<T, U> {
    fld1: T,
    fld2: PhantomData<U>,
}

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src\lib.rs:4:14
  |
4 |     unsafe { mem::transmute::<MyType<T, U1>, MyType<T, U2>>(src) }
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: source type: `MyType<T, U1>` (size can vary because of T)
  = note: target type: `MyType<T, U2>` (size can vary because of T)

パターン B2

ジェネリクス定数が関連するバグ

型の型パラメタに通常のものと未使用のジェネリクス定数が混在すると発生する。

ジェネリクス定数は未使用でもエラーにはならない。そして、本来なら未使用なのでそれが何であれサイズには関係ないはずである。しかし、なぜかこれを含むとサイズについて指摘されてしまう。

サンプル


use std::mem;

fn conv<T, const N: usize>(src: MyType<T, N>) -> MyType<T, 3> {
    unsafe { mem::transmute(src) }
}

pub struct MyType<T, const N: usize> {
    val: T,
}

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src\lib.rs:4:14
  |
4 |     unsafe { mem::transmute(src) }
  |              ^^^^^^^^^^^^^^
  |
  = note: source type: `MyType<T, N>` (size can vary because of T)
  = note: target type: `MyType<T, 3>` (size can vary because of T)