I'm talking when it was derived from a &mut reference.
Usually, it's safe to cast a const raw pointer derived from a mutable reference to a mut pointer. This can be used to share common code between &self and &mut self methods. For example:
impl<T: ?Sized> Something<T> {
pub fn get_ptr(this: *const Self) -> *const T {
// Just an example
this as *const T
}
pub fn get(&self) -> &T { unsafe { &*Self::get_ptr(self) } }
pub fn get_mut(&mut self) -> &mut T { unsafe { &mut *(Self::get_ptr(self as *mut Self) as *mut T) } }
}
Is it also valid when the get_ptr() function compose the pointer using the nightly std::ptr::from_raw_parts() or that the cycle breaks there, and I need from_raw_parts_mut()?
(Tangentially, IIRC that |it: &mut T| -> *const T { it } was (is?) a dangerous coercion since it may involve an implicitit as &T coercion, i.e., a &*it reborrow which changes provenance)
Not currently -- this is the coercion bug @Yandros mentioned. In both your example and from_raw_parts you hit the coercion. They wish it would work though.
I think you can just put my_mut_ref as *mut in there for it to be ok though? (I was trying to find confirmation but I'm going to post this right now instead since you just asked for a citation.)
Yeah, the main post is still an interesting question; I've currently been assuming that if a _mut variant exists, then there may be a reason, but I can't provide anything more concrete: I feel like we need to summon @RalfJung this time
Under my proposed aliasing model, only the initial cast from a reference to a raw ptr matters -- that must be reference as *mut _. Thereafter, it does not matter if you use *mut* or *const as long as it's all raw pointers. This includes methods like ptr::from_raw_parts since they use only raw pointers. It also includes addr_of! as long as you only take the address of fields -- once you actually follow an indirection, that's a totally unrelated pointer.
However, that is just my proposed model. There is nothing official currently.
I'll clarify one point here, regarding ptr::addr_of{,_mut}!, since I find this distinction to be a bit sneaky and thus able to catch some people off guard:
This means that while the following is fine under that model:
let mut it = (42_i32, 27_i32);
let p = &mut it as *mut _; // shared read-write over `(i32, i32)`.
unsafe {
// instead of `addr_of_mut!`
let snd = ptr::addr_of!( (*p).1 ) as *mut i32;
*snd += (*p).0;
}
The following is not "fine":
let mut it = (42, 27);
// instead of `addr_of_mut!`
let snd = ptr::addr_of!( it.1 ) as *mut i32;
unsafe {
*snd += it.0; // Error, mutating through a shared read-only
}
It think it's pretty obvious in hindsight, but it doesn't hurt to clarify. In that regard, addr_of_mut! is less error-prone, by checking the mut-accessiblity as if a &mut was being performed