There's surely cases where it would be hard to suggest a "equally efficient without UB" replacement (eg when it wants to fuse two i64 into one), but it feels like the current position is too far on the axis of "provided with suspicious code, the compiler should just make that garbage run as fast as possible and call it a day"
This article [0] goes into a bit more detail.
[0]: https://gist.github.com/rygorous/e0f055bfb74e3d5f0af20690759...
It's trivial to prove in that particular example because it's assumed that count is also an int (both i and count are in 32-bit registers).
> It also claims that the compiler cannot prove this in more complex examples (but gives no explicit examples).
The example doesn't even have to be that complex; you just need sizeof(n) > sizeof(i) and i to be signed (godbolt example at [0]). In that example, if the compiler can assume signed overflow is UB, then you get fairly sensible code generation. If the compiler cannot make that assumption (add the -fwrapv flag), then you get that movsxd instruction in the middle of the loop body. If you use -O2 instead of -O1, then -fwrapv prevents loop unrolling.
> What I'm saying is if the compiler cannot prove a lack of overflow in this way, that should be a warning.
I'm curious how frequently this warning might fire in real-life codebases, or when it does fire how frequently it's something the programmer can actually fix. Clang does have -Rpass-missed to emit some diagnostics when an optimization cannot be performed, but it doesn't emit anything in this particular case (though I'm not sure whether it's supposed to).
You'd hate a compiler where this has silly overhead:
That's because 64-bit addressing modes don't overflow the same way as signed 32-bit ints. But signed overflow being UB gives compilers license to ignore the difference and generate code that makes sense.The real problem is that C is too bare-bones and lax to be able to contain or avoid UB in day to day programs. For the aforementioned overflow gotcha, there's no way to enforce use of size_t for indexing. There's no `checked_mul(a,b)` to easily avoid signed UB. You have to make the check yourself, and if you're not careful, that check will be UB too. malloc() makes you multiply numbers often, exactly where it's dangerous. And on top of that implicit integer conversions can make unsigned arithmetic surprisingly signed.