c: Update nullptr_t comparison checks

WG14 has agreed to allow equality comparisons between pointers and
nullptr_t values that are not null pointer constants (this was
previously an exceptional case where such nullptr_t values were
handled differently from null pointer constants; other places in the
standard allowed nullptr_t values, whether or not those values are
null pointer constants, in the same contexts as null pointer
constants); see the wording at the end of N3077.  Update GCC's
implementation to match this change.

There are also changes to allow null pointer constants of integer or
pointer type to be converted to nullptr_t (by assignment, cast or
conversion as if by assignment), which I'll deal with separately.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c/
	* c-typeck.cc (build_binary_op): Allow comparisons between
	pointers and nullptr_t values that are not null pointer constants.

gcc/testsuite/
	* gcc.dg/c2x-constexpr-3.c: Do not expect comparison of nullptr_t
	and pointer to be disallowed.
	* gcc.dg/c2x-nullptr-1.c: Test comparisons of nullptr_t and
	pointers are allowed.
	* gcc.dg/c2x-nullptr-3.c: Do not test that comparisons of
	nullptr_t and pointers are disallowed.
This commit is contained in:
Joseph Myers 2023-02-02 23:29:45 +00:00
parent 07c87fce63
commit 0b8693fc87
4 changed files with 23 additions and 18 deletions

View file

@ -12749,12 +12749,16 @@ build_binary_op (location_t location, enum tree_code code,
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
else if (code0 == POINTER_TYPE
&& (code1 == NULLPTR_TYPE
|| null_pointer_constant_p (orig_op1)))
{
maybe_warn_for_null_address (location, op0, code);
result_type = type0;
}
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
else if (code1 == POINTER_TYPE
&& (code0 == NULLPTR_TYPE
|| null_pointer_constant_p (orig_op0)))
{
maybe_warn_for_null_address (location, op1, code);
result_type = type1;

View file

@ -219,7 +219,6 @@ f0 ()
(constexpr signed char []) { u8"\xff" }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
constexpr typeof (nullptr) not_npc = nullptr;
int *ptr = 0;
(void) (ptr == not_npc); /* { dg-error "invalid operands" } */
/* auto may only be used with another storage class specifier, such as
constexpr, if the type is inferred. */
auto constexpr int a_c_t = 1; /* { dg-error "'auto' used with 'constexpr'" } */

View file

@ -141,6 +141,23 @@ test2 (int *p)
(void) (p != _Generic(0, int : nullptr));
(void) (_Generic(0, int : nullptr) == p);
(void) (_Generic(0, int : nullptr) != p);
/* "(nullptr_t)nullptr" has type nullptr_t but isn't an NPC; these
comparisons are valid after C2X CD comments GB-071 and FR-073 were
resolved by the wording in N3077. */
(void) ((nullptr_t)nullptr == p);
(void) ((nullptr_t)nullptr != p);
(void) (p == (nullptr_t)nullptr);
(void) (p != (nullptr_t)nullptr);
(void) (cmp () == p);
(void) (cmp () != p);
(void) (p == cmp ());
(void) (p != cmp ());
/* "(void *)nullptr" is not an NPC, either. */
(void) ((void *)nullptr == cmp ());
(void) ((void *)nullptr != cmp ());
(void) (cmp () == (void *)nullptr);
(void) (cmp () != (void *)nullptr);
}
/* Test ?:. */

View file

@ -19,21 +19,6 @@ test1 (int *p)
(void) (nullptr != 1); /* { dg-error "invalid operands" } */
(void) (1 != nullptr); /* { dg-error "invalid operands" } */
(void) (1 > nullptr); /* { dg-error "invalid operands" } */
/* "(nullptr_t)nullptr" has type nullptr_t but isn't an NPC. */
(void) ((nullptr_t)nullptr == p); /* { dg-error "invalid operands" } */
(void) ((nullptr_t)nullptr != p); /* { dg-error "invalid operands" } */
(void) (p == (nullptr_t)nullptr); /* { dg-error "invalid operands" } */
(void) (p != (nullptr_t)nullptr); /* { dg-error "invalid operands" } */
(void) (cmp () == p); /* { dg-error "invalid operands" } */
(void) (cmp () != p); /* { dg-error "invalid operands" } */
(void) (p == cmp ()); /* { dg-error "invalid operands" } */
(void) (p != cmp ()); /* { dg-error "invalid operands" } */
/* "(void *)nullptr" is not an NPC, either. */
(void) ((void *)nullptr == cmp ()); /* { dg-error "invalid operands" } */
(void) ((void *)nullptr != cmp ()); /* { dg-error "invalid operands" } */
(void) (cmp () == (void *)nullptr); /* { dg-error "invalid operands" } */
(void) (cmp () != (void *)nullptr); /* { dg-error "invalid operands" } */
}
void