Take the following code
#include <iostream>
void func() {
    int i = 2147483640;
    while (i < i + 1)
    {
        std::cerr << i << '\n';
        ++i;
    }
    return;
}
int main() {
    func(); 
}
This code is clearly wrong, as the while loop can only terminate if the signed int i overflowed, which is UB, and hence the compiler may for instance optimize this into an infinite loop (which Clang does on -O3), or do other sorts of funky things. My question now is: from my reading of the C++ standard, types that are equivalent up to signedness may alias (i.e. pointers int* and unsigned* may alias). In order to do some funky signed "wrapping", does the following have undefined behavior or not?
#include <iostream>
static int safe_inc(int a)
{
    ++reinterpret_cast<unsigned&>(a);
    return a;
}
void func() {
    int i = 2147483640;
    while (i < safe_inc(i))
    {
        std::cerr << i << '\n';
        ++i;
    }
    return;
}
int main() {
    func(); 
}
I have tried the above code with both Clang 8 and GCC 9 on -O3 with -Wall -Wextra -Wpedantic -O3 -fsanitize=address,undefined arguments and get no errors or warnings and the loop terminates after wrapping to INT_MIN.
cppreference.com tells me that
Type aliasing
Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:
- AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType.
which from my reading means that for purposes of type aliasing, signedness is not considered, and the code using reinterpret_cast has well-defined semantics (albeit being somewhat cheesy anyhow).
 
     
     
    