Skip to content

std::mem::transmute doesn't compile even though both types are guaranteed to have the same size. #116585

@koenichiwa

Description

@koenichiwa

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-genericsArea: const generics (parameters and arguments)C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions