Arguably it’s not the compiled binary that’s “safe”. It’s the code.
Then the machine code generated by LLVM is not run directly by modern CPUs and is translated into internal representation first. And the future CPUs will behave like JIT-compilers with even more complex transformations.
The intermediate C code generated by this project just adds yet another transformation not fundamentally different from any of the above.
For example, signed overflow is UB in C, but defined in Rust. Generated code can't simply use the + operator.
C has type-based alias analysis that makes some type casts illegal. Rust handles alias analysis through borrowing, so it's more forgiving about type casts.
Rust has an UnsafeCell wrapper type for hacks that break the safe memory model and would be UB otherwise. C doesn't have such thing, so only uses of UnsafeCell that are already allowed by C are safe.
There are also escape hatches for strict aliasing in the C standard - mainly using memcpy for all memory operations.
For example, a C compiler is allowed to optimize the expression a+1<a to false (if a is signed), but a Rust compiler isn't allowed to do this.
> For example, signed overflow is UB in C, but defined in Rust. Generated code can't simply use the + operator.
Obviously, yes, but it could generate overflow checks.