Coercing references to raw pointers involves borrow checking


#1

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?


#2

A one-time bump in case someone with a good explanation/viewpoint missed this first time around.


#3

To me this sounds like a reasonable interpretation, especially for transmute since it is a function call. Maybe the borrow checker could ignore coercions to raw pointers without impacting soundness, but if it did so ISTM this would probably require special casing.


#4

transmute is already an intrinsic so compiler knows about it. But yeah, borrowck would presumably need to ignore such uses (if this is indeed the reason it doesn’t work).

The current scheme seems a bit undesirable because the raw ptr coercion/cast needs to be done in a place where you might not naturally place it otherwise.