It is an error to access a place, when an access conflicts with a loan, and the loan is live.
In fact there are an infinite number of correct Rust programs which will never access memory incorrectly but which will still be rejected by the compiler, for the simple reason that Rust's authors, talented though they may be, have made no progress at all at solving the Halting Problem.
What Rust actually accepts is a subset of correct programs. And this subset is somewhat informally defined as "whatever the compiler could manage to prove". Real code hits against this limit occasionally, and when it does there's really no option other than "join the Rust team" or "try voodoo".
The unstated problem is that there are patterns from other languages that are actually invalid and Rust is correctly denying, but not properly communicating it, which causes frustration. You can always make the argument that the failure modes are benign or rare, and for those cases noone is stopping you from actually using unsafe.
[1]: https://manishearth.github.io/blog/2015/05/27/wrapper-types-...
And this is why this argument persists. This is, to people outside the community, a semantic evasion:
1. It relies on a Rust-internal definition for "actually valid" (conforming to Rust's specific set of provability requirements) that doesn't correspond to what the rest of the world views as "correct" (not behaving incorrectly). Think about stuff like allocate-through-a-session-and-free-in-a-block paradigms (Apache was famous for this), or run-once-and-exit, or garbage collection, etc... Those things aren't "invalid" in any reasonable sense, they're just not what Rust programs do.
2. The definition for "valid" is (and this is my point above) entirely Rust-internal and ad hoc. It's not that we refuse to conform to your rules, really, it's that we don't know what they are!
Like all type checking technology, the rule is about static behavior, not dynamic behavior. So halting problem is irrelevant.
Rust accepts all programs that follow the rule in static behavior. It's not a subset, and it's not a best effort to prove. It's the complete statement.
"Access" means source code construct to read or write. Rust doesn't care whether the construct is actually executed in runtime.
let (left, right) = (&mut foo[..split], &mut foo[split..]);
where you have to rely on things like foo.split_at_mut(split), which are implemented as unsafe under the cover.I see these are limitations but not show-stoppers in any way.