Yes, that "clear set of logical rules" is called the Rust ownership and lifetime system, and the system that enforces it is called the borrow check. And, having designed a lot of Rust's borrow rules, I'm telling you that the borrow check only works because of the specific rules that Rust enforces: in particular, no more than one mutable pointer to a location. Non-Rust languages don't enforce those rules, so grafting the Rust borrow check onto the language will rule out a lot of idiomatic code. For example, in C++, you would be unable to write shared_ptr<T> for non-const T (this is just one of a mountain of examples), and I'm sure that the situation would be similar in Zig once you start diving into the details.
I'm much more interested in specific details of how to permit mutable aliasing while simultaneously avoiding use-after-free. From what I've seen, the only compelling answer is a garbage collector.
I think your concept of what is possible with languages is limited and you are suffering from either narrow tunnel vision or some sort of emotional overinvestment in what you've put effort into. I don't know what the right answer is. It could be as complicated as something like SEL4 does, it could be like typescript is for JavaScript, it could be annotation based like dialyzer is for Erlang. Not all of these are perfect, of course, but the point is is a wide open space of tradeoffs in safety, performance, and ergonomics (including ability to reason about scary vulnerabilities that rust can't auto fix like race conditions or business logic errord) between "what rust looks like" and "c level wild west".
So far no language not designed for it has demonstrated that adopting a borrow-checker to interesting real-world use-cases is possible. The C++ project (C++ Core Guidelines it is called IIRC) eventually gave up on soundness. Zig isn't there yet, I am very curious how they will tackle this.
So, I'm not going to use the word "impossible", but I think this is a hard problem and many people are underestimating how hard it is. It is strictly harder than what Rust is attempting, and see all the tricks they had to pull!
Put differently, if you are right, it should be easy to prove pcwalton wrong by just doing it. :)
I mean, I don't think they were claiming the rust way is the only possible form, but rather that any solution as expressive and safe as the rust method will be about as complicated, which doesn't seem to disagree all that much with what you are saying to be honest.
The interesting question is whether there exists some system fundamentally/significantly simpler than the rust approach which still gives you comparable freedom and safety (without excessive runtime overhead).
As far as I know that is unsolved and a matter for research, not some obvious solution that the rust team totally missed when designing their language.
If your goal is lower than total memory safety, then obviously you'll have more options, but when it comes to memory models, you have to be quite careful in where you allow violations, since they tend to infect everything quickly if you don't find exactly the right way to encapsulate them, so having a "half-safe" language often just means you have an unsafe language. Part of the reason unsafe rust is so painful is they're adding exactly that sort of hole in the memory model, and suddenly anyone exposed to it can't deal with the "simple" memory model of rust, they have to deal with all the gory details _creating_ that simple model. Any language adding larger holes than unsafe will need more people to be aware of the full complexity of modern compilation more of the time, which doesn't seem like a win. Rust's unsafe works because it's almost never used. If unsafe was half the codebase, rust would be a failed language.
Another solution is to absolutely refuse to take advantage of your safer memory model in the compiler - so minimal optimizations, just compile literally and throw barriers all over the code, then anyone using a downgraded model doesn't need to know the additional rules they would otherwise need to follow to interact with the full model. That sounds pretty awful though, probably more expensive than just using a garbage collector.
Is there a better solution? Sure, probably, but I don't think humanity has discovered it yet.
The real problem is pretty much any model that doesn't shoot for complete memory safety (or a unsafety that is strongly discouraged and well encapsulated) is going to end up containing all the complexity that comes from unsafety, rust justifies its complexity by all the complexity it also removed (undefined behaviour is basically not a thing in Rust), if you half the complexity compared to rust but retain half the undefined behaviour complexity of C++, I think you'll have just grafted the worst of both together. I'm unconvinced there's a sweet spot in the middle, more like a mountain of extreme complexity (ala rust unsafe) between 2 valleys of relative simplicity (C-like, rust-like).
I'm much more interested in specific details of how to permit mutable aliasing while simultaneously avoiding use-after-free. From what I've seen, the only compelling answer is a garbage collector.