Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transmute moved the parameter of "&mut f32" type #87276

Closed
psionic12 opened this issue Jul 19, 2021 · 5 comments
Closed

transmute moved the parameter of "&mut f32" type #87276

psionic12 opened this issue Jul 19, 2021 · 5 comments
Labels
C-bug Category: This is a bug.

Comments

@psionic12
Copy link

reproduced code:

unsafe fn foo (v: &mut f32, ptr: *const u8) {
    // let dst : *mut u8 = transmute::<&mut f32, *mut u8>(v); // this line work fine, no error reported by the compiler
    let dst : *mut u8 = transmute(v);
    std::ptr::copy_nonoverlapping(ptr, dst, 4);
    v.to_le_bytes();
}

the reported error is:

error[E0382]: use of moved value: `v`
  --> src/main.rs:12:5
   |
8  | unsafe fn foo (v: &mut f32, ptr: *const u8) {
   |                - move occurs because `v` has type `&mut f32`, which does not implement the `Copy` trait
9  |     // let dst : *mut u8 = transmute::<&mut f32, *mut u8>(v);
10 |     let dst : *mut u8 = transmute(v);
   |                                   - value moved here
11 |     std::ptr::copy_nonoverlapping(ptr, dst, 4);
12 |     v.to_le_bytes();
   |     ^ value used here after move

Rust version:

rustc 1.53.0 (53cb7b09b 2021-06-17)
binary: rustc
commit-hash: 53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b
commit-date: 2021-06-17
host: x86_64-apple-darwin
release: 1.53.0
LLVM version: 12.0.1
@psionic12 psionic12 added the C-bug Category: This is a bug. label Jul 19, 2021
@fee1-dead
Copy link
Member

Why do you think it is a bug? Transmute does move the reference. Are you looking for:

let dst = v as *mut f32 as *mut u8;

?

@psionic12
Copy link
Author

So why let dst : *mut u8 = transmute::<&mut f32, *mut u8>(v); compiles in my case? Anything different with let dst : *mut u8 = transmute(v);?

@SkiFire13
Copy link
Contributor

We often forget that &mut T is neither Clone nor Copy thanks to automatic reborrowing inserted by the compiler. When you do transmute::<&mut f32, *mut u8>(v) the &mut f32 you specify can and actually gets a lifetime shorter than the one of v, and v gets reborrowed and not consumed. However this doesn't happen when you write transmute(v) because the T on transmute is expected to have the exact same type as v, thus the same lifetime, and no reborrowing can occur. There isn't a lot of documentation on reborrowing (see rust-lang/reference#788), but my understanding is that it kinda works like a coercion (it kinda looks like a subtype coercion, except it doesn't consume). In fact arguments of functions are coercion sites, but only if they don't expect a generic type (see the second half of https://doc.rust-lang.org/nomicon/coercions.html).

@psionic12
Copy link
Author

@SkiFire13 Thanks for pointing out the concept "coercions".

Since transmute is an intrinsic and act like as, the borrow rules here looks kind of cumbersome to me...

Maybe a key word like reinterpret_cast would be better...

@SkiFire13
Copy link
Contributor

transmute doesn't act like as, for the purpose of typechecking it is like any other function. The borrowing rules here don't look cumbersome to me, being able to reuse a consumed value after it has been consumed is IMO a potential footgun and transmute shouldn't allow that.

I don't see how reinterpret_cast would really be better. Do we really need to add a new keyword for that? Do we really need to deprecate something that works fine?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants