c++pointersc++20comparison-operatorsnullptr

p > nullptr: Undefined behavior?


The following flawed code for a null pointer check compiles with some compilers but not with others (see godbolt):

bool f()
{
    char c;
    return &c > nullptr;
}

The offensive part is the relational comparison between a pointer and nullptr.

The comparison compiles with

But no version of clang (I checked down to 4.0) compiles it.

The error newer gccs produce ("ordered comparison of pointer with integer zero ('char*' and 'std::nullptr_t')"1 is a bit different than the one from clang ("invalid operands to binary expression ('char *' and 'std::nullptr_t')").

The C++20 ISO standard says about relational operators applied to pointers in 7.6.9/3ff:

If both operands are pointers, pointer conversions (7.3.12) [...] are performed to bring them to their composite pointer type (7.2.2). After conversions, the operands shall have the same type.

The result of comparing unequal pointers to objects is defined in terms of a partial order consistent with the following rules:

(4.1) — If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.
(4.2) — If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member is required to compare greater provided the two members have the same access control (11.9), neither member is a subobject of zero size, and their class is not a union.
(4.3) — Otherwise, neither pointer is required to compare greater than the other.

("Pointer to object" in this context means only that the type is not a pointer to function, not that the pointer value refers to an actual object.)

(4.1) and (4.2) clearly don't apply here, which leaves (4.3). Does (4.3), "neither pointer is required", mean the behavior is undefined, and the code is invalid? By comparison, the 2012 standard contained the wording in 5.9/2 "[...] if only one of [two pointers of the same type p and q] is null, the results of p<q, p>q, p<=q, and p>=q are unspecified."


1 The wording doesn't seem correct. nullptr_t is not, if I read the standard correctly, an integral type.


Solution

  • 7.6.9 states, "The lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) standard conversions are performed on the operands. .... The converted operands shall have arithmetic, enumeration, or pointer type."

    None of the specified conversions is applicable to the literal nullptr. Also, it does not have arithmetic, enumeration, or pointer type. Therefore, the comparison is ill-formed.