I finally understood your point and where I was unclear, mostly after reading the other comment about the for loop.
You're right that C requires UB to optimize things like (x2)/2. My argument is that Go and Rust's secret sauce is you wouldn't have to write things spiritually similar to that in the first place. (x2)/2 is a bad example, since nobody would write that on purpose, but loops are a great one. C's only interface to elements of an array is a pointer. So C has to say that accessing out-of-bounds pointers are UB, as is even having a pointer that's neither in-bounds or right at the end, because it simply has no way to distinguish "pointer" from "pointer that is in-bounds for this array". The type of an array iterator in Rust (and I think also Go) carries knowledge of what array it's iterating over, and how far it can iterate; since it's part of the type system, the compiler has access to that knowledge. So you can just say `for element in array`, and the compiler knows that you're only accessing in-bounds pointers, and generate the same code C would, without needing to define a concept of UB.
Of course if you do generate pointers in unsafe code, you are subject to UB, same as in C. Rust and Go simply give you a language where most of the time, you don't need to reach for constructs that require UB to be performant.
(There is, however, an actual bit of secret sauce, at least in Rust but I suspect Go has an analogue: Rust's ownership system allows it to do far stronger alias analysis than even C's -fstrict-aliasing, without the risk of false positives -- you cannot construct overlapping mutable pointers in safe code.)
You're right that C requires UB to optimize things like (x2)/2. My argument is that Go and Rust's secret sauce is you wouldn't have to write things spiritually similar to that in the first place. (x2)/2 is a bad example, since nobody would write that on purpose, but loops are a great one. C's only interface to elements of an array is a pointer. So C has to say that accessing out-of-bounds pointers are UB, as is even having a pointer that's neither in-bounds or right at the end, because it simply has no way to distinguish "pointer" from "pointer that is in-bounds for this array". The type of an array iterator in Rust (and I think also Go) carries knowledge of what array it's iterating over, and how far it can iterate; since it's part of the type system, the compiler has access to that knowledge. So you can just say `for element in array`, and the compiler knows that you're only accessing in-bounds pointers, and generate the same code C would, without needing to define a concept of UB.
Of course if you do generate pointers in unsafe code, you are subject to UB, same as in C. Rust and Go simply give you a language where most of the time, you don't need to reach for constructs that require UB to be performant.
(There is, however, an actual bit of secret sauce, at least in Rust but I suspect Go has an analogue: Rust's ownership system allows it to do far stronger alias analysis than even C's -fstrict-aliasing, without the risk of false positives -- you cannot construct overlapping mutable pointers in safe code.)