Consider the following (super contrived but illustratory) code, which is the classic “return from a function doesn’t drop the borrow”:
struct MyVec(Vec<String>);
impl MyVec {
fn get_or_insert(&mut self) -> &mut String {
if let Some(s) = self.0.iter_mut().find(|s| &**s == "foo") {
return s;
}
unsafe {
let me: *mut Self = self;
// this is a stub - real code would deref the raw ptr and mutate the Vec
unimplemented!()
}
}
}
This fails to compile because the borrow checker is disallowing the raw ptr coercion due to self
still being borrowed mutably (that’s fixed by NLL but that’s somewhat beside the point). The compiler also isn’t happy with trying to transmute to a raw ptr for the same reason.
Now, I understand that unsafe blocks don’t disable the borrowck - use of references in an unsafe block is still checked. And technically I don’t even need an unsafe block to coerce (or cast) to a raw ptr, only to deref it. But I tried a transmute there, which does, and just left the code as-is.
The above code can be made to work if the coercion to the raw ptr is done before the borrow is extended out to the caller - basically as the first thing in the method.
Given that raw ptrs, after they’re formed, aren’t tracked by any ownership (amongst other) rules, it seems a bit odd that to get one in the first place involves the borrow checker.
What’s the rationale for this? Or is the coercion (or cast or transmute) to a raw ptr considered a “use of a reference” and being checked just falls out of normal rules?