In the following code I tested which form of overflow results in UB and causes therefore
an hard error in a constexpr context:
#include <cstdint>
#include <limits>
using T = int8_t;
int main() {
constexpr bool b = []{
T x = std::numeric_limits<T>::max();
++x; // GCC: UB, Clang: no UB
// x += 1;
// x = x + 1;
return (x > std::numeric_limits<T>::max());
}();
return b;
}
The preincrement gives an error (as I expected) for gcc but not for clang.
More strange is that the standard says that ++x is the same as x += 1, but using this gives no more an error on gcc (and clang as before).
And further x += 1 should be the same as x = x + 1, so the rhs is promoted to int and the result is implicitly converted. So, this should newer be UB.
So, the question is, which of the three statement really should be UB (I think only ++x) and which compiler is correct?
x = x + 1is well defined.x + 1promoted tointfirst so no overflow happens and the assignment back toint8_tis now defined to work modulo 2^n. Whether that applies tox += 1and++xtoo I leave to the language lawyers.int8_thas been defined as two's-complement so the result of overflow should never be in question. It's silly C++ still calls it UB, stupid integer promotion breaking it all.