MushyQuadrant
If the compiler has some special knowledge of the target architecture which makes the second form behave as if the first form was executed (such as if NULL is a valid address on the target architecture), it may make the transformation, but that still wouldn't cause undefined behavior, because it must behave as if it had the first form.
Since, in the process of optimization, optimizing compilers make conclusions about parts of a program based on other parts of the program which may be executed later, undefined behavior in one part of a program causes invalid conclusions about other parts which may be executed earlier. Therefore undefined behavior cannot be contained to just parts of a program executed after a particular part, if the compiler tries to optimize parts of the program based on parts that may be executed later.
Perhaps this is true, or perhaps you are just unaware of the undefined behavior you have relied on.
What I can say for sure, is that all of the non-trivial C++ programs written by a large team which I have worked on in my career have invoked some undefined behavior. Usually, the compiler does do "the right thing" despite the error, but sometimes it blows up in our face, and causes incredibly hard to debug bugs, such as a pointer appearing to simultaneously point to two different addresses, because an array was declared as two different sizes in two different translation units.
Even when I spot the instances of undefined behavior, it's often hard to convince other developers that, although this seems to behave correctly now, it could break in unexpected, hard to debug ways at any time in the future.
For example, imagine a C programmer writes a function that adds two `int` values. Hypothetically, with some inputs, the addition may overflow. That would be undefined behavior, so the compiler assumes the function is never called with such inputs, and optimizes accordingly. The programmer knows this, and assures the function is never called with those inputs. Since the only assumption the compiler made was that the function wasn't called with input which would cause the addition to overflow, and the programmer assured that assumption is correct, the function always behaves correctly.
Consider if the same function's inputs were provided at runtime from stdin. The behavior of the whole program is undefined if invalid inputs are given, but if only valid inputs are given, the program must behave correctly.