| > Would you like a warning every time the compiler made your loops faster by relying on this UB? Yes, because then I know to convert the loop counter to unsigned, which it ought to be anyway so that there isn't problematic behavior if the signed value actually did overflow when using a compiler or compiler flags that don't take that optimization. > Every time a pointer is dereferenced? Every time a pointer is dereferenced and the compiler uses that fact to cause some other statement to have no effect? I want to see that warning, yes. > You put "optimization" in quotes but that's exactly what this is about - in practice it would make tons of code (in particular loops) significantly slower to eliminate this UB. That's an argument for why it shouldn't be two's complement, not for why it has to be fully undefined behavior. If you're going to make signed integers never overflow when used as a loop counter, what's wrong with documenting that and offering a warning in -Wall or -Wextra when it happens? And it's nothing specifically to do with signed integer overflow. If you're removing code the programmer wrote or making conditional statements unconditional because it can only happen in the presence of UB, that's a huge red flag that there is a bug in that program and the compiler should not be silent about it. |
See below.
> Every time a pointer is dereferenced and the compiler uses that fact to cause some other statement to have no effect?
No, every time any logic in the compiler does any UB-based inference. And that's essentially always. For example, you can't reorder variables unless you assume the abstract machine semantics and memory model. You can't elide repeated loads either. And eliding reloads is a very simple case of some expression having no effect.
More generally, for every compiler optimization I can tell you a UB source that breaks that optimization (i.e. a UB-backed guarantee of the standard that the compiler has to rely on). So should we not do any compiler optimizations at all? That's freely available to you in every compiler.
> That's an argument for why it shouldn't be two's complement, not for why it has to be fully undefined behavior.
Sorry, I don't understand your point. Why should integers not be two's complement? How would that help?
> If you're going to make signed integers never overflow when used as a loop counter, what's wrong with documenting that and offering a warning in -Wall or -Wextra when it happens?
What do you mean "when it happens"? The compiler can't in general determine at compile-time whether a loop counter will overflow. Are you suggesting all loops with signed counter should produce a warning because everyone should be using unsigned loops? If you want slow-but-safe-by-default language then you are simply at the wrong address with C++.
> If you're removing code the programmer wrote...
That's essentially the compiler's whole point. Cut through all the abstraction and generate efficient machine code. Yes, I want that three-iteration loop unrolled, I don't actually intend to perform 3 increments and 4 comparisons (and special overflow handling) in machine code. Yes, I want all those container access functions (full of unspoken range assumptions) or recursive variadic templates (full of unconditionally-false-once-expanded ifs) inlined and not appearing at all in the assembly. Try running a no-optimizations build of any larger piece of C++ software and see what I mean.
> ...or making conditional statements unconditional because it can only happen in the presence of UB that's a huge red flag that there is a bug in that program and the compiler should not be silent about it.
You're thinking of trivial situations where the compiler could reasonably guess that relying on UB causes an unwanted optimization. But you can't build a compiler around only the nice and happy cases - what if that situation occurs 4 levels deep in some template code where 3 other functions were already inlined and the compiler can see that in that specific case some condition cannot be true without UB. Would you like a warning about every such case?
It's just not the compiler's job to second-guess your code. There are tools (specifically linters) that are built to detect these easy cases you're thinking of and help you find these bugs (but they won't help you with bugs in the hard cases either).