Yep. In the ereport() example, though, it’s even simpler: the program couldn’t execute undefined behavior given
any input, because ereport() calls abort() if the error level is ERROR (as is the case here). There’s a statement syntactically following the ereport() which would be UB if it were executed, and since ereport isn’t marked noreturn, the compiler can’t prove that it won’t be executed. But that’s not the right standard: the optimization is only justified if the compiler
can prove that it
will be executed (under the assumption that control flow has reached the code whose observable behavior is being altered).
Edit: that is, with any input that causes it to be altered. The most famous cases of UB involve compilers removing code entirely or optimizing an expression to a constant, but it’s just as valid (and more useful) to replace one computation with another computation (e.g. an unsigned division with a signed division) that produces the same result for “legal” inputs, but potentially a different result for “illegal” inputs – where “illegal” means “given that input at that point in the program, the program necessarily has executed or will execute UB”. From the standard’s perspective, the question is not which instructions are generated or what computations are actually performed, but whether the observable behavior is the same “as if” the computations in the source code were performed, for all execution traces not containing UB. (Just to reword myself in increasingly verbose fashion.)