Doesn’t the BTreeMap iterator use raw pointers for the root and node? Even if the rule were that “no &mut reference can alias any other reference once one leaves the unsafe block”, I don’t see how that would affect BTreeMap. Indeed, I think that like in the Ref case, raw pointers are the correct solution when one wants to keep a pointer that does not meet the type-system requirements for & or &mut.
The more I think about this problem, the more I like the solution of “type-system invariants must hold outside of an unsafe block. Code within an unsafe block is free to break these invariants, but they must be restored before leaving the block.” The easiest way to do this is to have any variables that violate type invariants scoped within the unsafe block. To me, this seems like a simple rule that is easy to remember, and the boundaries are simple and obvious (the unsafe block, itself). Indeed, it is what I would intuitively expect and try to uphold in my own code. It’s true that the unsafe block would have to be careful not to expose broken invariants to any safe functions it might call (e.g., it couldn’t pass two aliasing &muts to a safe function), but not exposing invariants to code outside the boundary is necessary for any boundary.
The split-at-mut-via-duplication example can trivially be made to follow this rule by expanding the unsafe block:
impl [T] {
pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
unsafe {
let copy: &mut [T] = &mut *(self as *mut _);
let left = &mut self[0..mid];
let right = &mut copy[mid..];
(left, right)
}
}
}
Note that due to scoping, even in the event of a panic, no code outside of the unsafe block can observe aliasing.
I don’t think an author failing to follow a rule that was not thought out at the time, and which we are just now trying to formulate, is a sign of doom. I agree with @arielb1 that this code appears to be pretty obviously invalid, as the lifetime on the reference is just plain wrong. As I have mentioned before, I think trying to make this case valid should be a non-goal. Further, I think that once we have the rules regarding type-system invariants and unsafe written down, including examples such as invalid lifetimes and aliasing &muts, it will be very unlikely that such code with be written or pass code review.