Search code examples
c++c++17language-lawyerconstexprdangling-pointer

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


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?


Solution

  • 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. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. 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.