Per-module unsafety rules just feel kind of totally random, especially because modules do not matter to semantics in any other way.
Unsafe code is often used in places where no invariants can possibly be broken (unchecked_get and friends, FFI with raw pointers), and random de-optimization there would be very annoying.
This is made worse by the problems we are trying to bypass being basically local. Even if we take our consume_from_usize example:
pub fn entry_point() {
let x: i32 = 2;
let p: usize = escape_as_usize(&x);
println!("{}", unsafe { consume_from_usize(p) });
}
It is very similar to:
pub fn entry_point() {
let mut x: i32 = 2;
let x_ref = &mut x;
let p: usize = escape_as_usize(&*x_ref);
println!("{}", unsafe { consume_from_usize(p) });
}
Here, the problem is obviously that we read x while there is a mutable reference to it, and the question is whether the mutable reference is active or not. I think we can treat the Var(x) lvalue basically as a scope-long mutable borrow, which would make these examples completely equivalent.