error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
transmute
関数の入力型と出力型でサイズが一致していない。
transmute
関数は型変換系のメソッドでビット列はそのままに型変換した事にする。
もちろんこの関数は unsafe
である。また、他の unsafe
な機能と比べても、誤用すると意味不明な挙動になりやすく、より危険である。そのため、なるべくこの関数を使わないで済むように std
や core
では多くの実用的な変換がすでに用意されている。
そして、この関数は入力型と出力型のサイズが異なる場合、コンパイルエラーを発生させる (2025 年現在、Rust はユーザにはこうした型チェックを提供しないため、この関数は特別な扱いをされているようだ)。なお、この安全策すら取り払った transmute_copy
もある。
実際に入力型と出力型のサイズが異なるパターン。
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)
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)
型の型パラメタに通常のものと未使用のジェネリクス定数が混在すると発生する。
ジェネリクス定数は未使用でもエラーにはならない。そして、本来なら未使用なのでそれが何であれサイズには関係ないはずである。しかし、なぜかこれを含むとサイズについて指摘されてしまう。
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)