Reputation: 135
This piece of code is correct:
fn f() {
let mut x = 11;
b(&x as *const u8 as *mut u8);
}
fn b(x: *mut u8) {}
Why is b(&x as *const u8 as *mut u8)
is valid whereas b(&x as *mut u8)
is invalid? The compiler complains about:
error[E0606]: casting
&u8
as*mut u8
is invalid
Upvotes: 5
Views: 4988
Reputation: 357
Because a rust reference is constant.
What you want to do is to cast a mutable reference &mut x
to a raw integer mutable pointer *mut i32
.
This code is valid:
let mut x = 42;
let ptr = &mut x as *mut _;
// equivalent to
let ptr_2 = &x as *const _ as *mut _;
Upvotes: 0
Reputation: 602355
The superficial answer to the question "why?" is that these simply are the rules of as
expressions in Rust. Quoting from the Nomicon:
Casting is not transitive, that is, even if
e as U1 as U2
is a valid expression,e as U2
is not necessarily so.
With the as
operator, you can either perform explicit coercions or casts.
There is neither a cast nor a coercion to go directly from &u8
to *mut u8
. However, there is a pointer weakening coercion from &T
to *const T
and a cast from a pointer to a sized type to any other. The combination of the two results in the expression in your question.
The deeper question is why the language was designed this way. I don't actually know, since I wasn't in the room when these decisions were made, and I couldn't find a rationale on the web. Rust in general tries to be very explicit with type casts, to avoid conversions that weren't actually intended and to keep the rules simple. These princilpes seem to have influenced this particular design decision as well.
Upvotes: 10