"&mut -> *mut" conversion vs. std::mem::transmute


#1

Consider the following two functions:

unsafe fn f1(a: &mut u32) {
    let ptr1: *mut u32 = std::mem::transmute(a);
    *a = 1;
}

unsafe fn f2(a: &mut u32) {
    let ptr1: *mut u32 = a;
    *a = 1;
}

With current Rust, the first gives a borrowck error, the second doesn’t. The behavior of transmute is easy to understand: it consumes the reference, so future uses will go through the pointer instead. The conversion, on the other hand, is like transmute_copy: it gives you a pointer, but the original reference is still valid. This seems ridiculous: why does the simpler version default to behavior equivalent to transmute_copy?

If we changed the borrow checker to treat f1 and f2 the same way, it would make split-at-mut-via-duplication from http://smallcultfollowing.com/babysteps/blog/2016/05/27/the-tootsie-pop-model-for-unsafe-code/ simply illegal, so nobody could make a mistake like that.

If you actually want the old behavior, you could still write let ptr1 : *mut u32 = &mut *a;.

Has something like this been discussed before?


#2

This would make a lot of FFI code pretty painful to work with, I think. It’s very common to do things like some_c_fn(p) where p: &mut T but some_c_fn expects a *mut T.


#3

And of course, the way I initially wrote the example, it used transmute_copy =)