Can dangling pointer be equal to valid pointer during constant evaluation in C++?

Viewed 228

During constant expression evaluation in C++17, shall the compiler consider any pointer addressing a valid object unequal to any pointer addressing an object after the end of its lifetime?

For example:

constexpr auto f(int * x = nullptr) {
    int c = 0;
    auto p = &c;
    if ( x == p )
        throw "unexpected";
    return p;
};

int main() {
    static_assert( f( f() ) );
}

Here the inner call of function f() returns a dangling pointer, which is passed to f again. I believed that the condition x == p must be false since x is a dangling pointer and p is a valid pointer, and it is indeed so in Clang. But in GCC the condition is satisfied and the constant evaluation fails due to throw. Demo: https://gcc.godbolt.org/z/ehcMro17q

Is it an undefined or implementation-defined behavior, or one of the compilers is wrong?

1 Answers

The result of comparing a dangling pointer with any other pointer is implementation-defined:

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values. […] Any other use of an invalid pointer value has implementation-defined behavior.

([basic.stc]/4) (equality comparison is included in “other use” here.)

As noted in the comments, even the lvalue-to-rvalue conversion of the comparison operands invokes implementation-defined behaviour for the invalid pointer ([conv.lval]/3.3). Unfortunately I can’t find anything that mandates lvalue-to-rvalue conversion for the operands of an equality comparison; [expr.eq]/2 at best implies this very indirectly.

Related