-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
Let me preface that I'm actively looking into other options than transmute, but I expected this to work, because it could basically be an no-op. Also the doc on transmute
says: "Compilation will fail if this is not guaranteed", and these types are essentially the same.
I'm working on a Builder
derive and I'm working on the implementation of the setters. I was trying something new.
I tried this code:
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn bar(mut self, bar: [usize; SIZE]) -> FooBuilder<SIZE, true> {
self.data.bar = Some(bar);
unsafe { std::mem::transmute(self) }
}
}
It's part of a bigger piece of code:
// simplified macro expansion:
pub struct Foo<const SIZE: usize> {
bar: [usize; SIZE],
}
pub struct FooData<const SIZE: usize> {
pub bar: Option<[usize; SIZE]>,
}
impl<const SIZE: usize> Builder for Foo<SIZE> {
type Builder = FooBuilder<SIZE, false>;
fn builder() -> FooBuilder<SIZE, false> {
self::Builder::new()
}
}
pub struct FooBuilder<const SIZE: usize, const __BUILDER_CONST_0: bool> {
data: FooData<SIZE>,
}
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn new() -> FooBuilder<SIZE, false> {
data: FooData<SIZE> {
bar: None,
}
}
}
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn bar(mut self, bar: [usize; SIZE]) -> FooBuilder<SIZE, true> {
self.data.bar = Some(bar);
unsafe { std::mem::transmute(self) }
// ^^^^^^^^^^^^^^^^^^^ Here I call the transmute
}
}
impl<const SIZE: usize> FooBuilder<SIZE, true> {
pub fn build(self) -> Foo<SIZE> {
Foo<SIZE> {
bar: self.data.bar.unwrap()
}
}
}
I expected to see this happen: Because both the input and the output are guaranteed to be the same size, I expected it to compile.
Instead, this happened: It didn't compile, and I got this error:
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> const_typed_builder_test/src/lib.rs:693:32
|
693 | #[derive(Debug, PartialEq, Builder)]
| ^^^^^^^
|
= note: source type: `test::const_generic::FooBuilder<SIZE, false>` (size can vary because of [usize; SIZE])
= note: target type: `test::const_generic::FooBuilder<SIZE, true>` (size can vary because of [usize; SIZE])
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
Meta
rustc --version --verbose
:
rustc 1.74.0-beta.1 (b5c050feb 2023-10-03)
binary: rustc
commit-hash: b5c050febf10c9bcc0459d41fe2a1e190ad30b8d
commit-date: 2023-10-03
host: x86_64-apple-darwin
release: 1.74.0-beta.1
LLVM version: 17.0.2
I also ran it on the latest nigthly and stable, with the same response
rustc 1.75.0-nightly (2e5a9dd6c 2023-10-02)
binary: rustc
commit-hash: 2e5a9dd6c9eaa42f0684b4b760bd68fc27cbe51b
commit-date: 2023-10-02
host: x86_64-apple-darwin
release: 1.75.0-nightly
LLVM version: 17.0.2
rustc 1.72.1 (d5c2e9c34 2023-09-13)
binary: rustc
commit-hash: d5c2e9c342b358556da91d61ed4133f6f50fc0c3
commit-date: 2023-09-13
host: x86_64-apple-darwin
release: 1.72.1
LLVM version: 16.0.5
Backtrace
I'm not sure what I'm doing wrong but if I run `cargo test --workspace -- -Z macro-backtrace` I only get this:
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> const_typed_builder_test/src/lib.rs:693:32
|
693 | #[derive(Debug, PartialEq, Builder)]
| ^^^^^^^
|
= note: source type: `test::const_generic::FooBuilder<SIZE, false>` (size can vary because of [usize; SIZE])
= note: target type: `test::const_generic::FooBuilder<SIZE, true>` (size can vary because of [usize; SIZE])
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)