So the problem is not that GCC assumes your code has no UB.
The issue is that the C (and C++) specifications persist in this obnoxious and odious desire to label definable behaviour as UB, with no justification.
All of the arguments about needing UB to support different hardware fail immediately to the simple fact that the specification already has specific terms that would cover this: Implementation Defined Behavior, and Unspecified Behaviour. Using either of these instead of UB would support just as much hardware, without inflicting clearly anti-programmer optimizations on developers where the compiler is allowed to assume objectively false things about the hardware.
Undefined behaviour should be used solely for behavior that cannot be defined - for example using out of bounds, unallocated, or released memory cannot be defined because the C VM does not specify allocation, variable allocation, etc. Calling a function with a mismatched type signature is not definable as C does not specify the ABI. etc.