aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2023-02-10 00:42:47 +0000
committerJoseph Myers <joseph@codesourcery.com>2023-02-10 00:42:47 +0000
commitb9f8935e110c392c21460db838b4209c32f070c2 (patch)
tree329ad18e382724a5d148e1cb74b5f66fec86d69e
parent41015797ad14bc9030a87d102e4ab1ad891345f6 (diff)
downloadgcc-b9f8935e110c392c21460db838b4209c32f070c2.zip
gcc-b9f8935e110c392c21460db838b4209c32f070c2.tar.gz
gcc-b9f8935e110c392c21460db838b4209c32f070c2.tar.bz2
c: Allow conversions of null pointer constants to nullptr_t
WG14 has agreed to allow conversions (explicit and implicit) from null pointer constants to nullptr_t; update GCC's nullptr_t implementation to match. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c/ * c-convert.cc (c_convert): Allow conversion of a null pointer constant to nullptr_t. * c-typeck.cc (null_pointer_constant_p): Remove static. (convert_for_assignment): Allow conversion of a null pointer constant to nullptr_t. (digest_init): Handle NULLPTR_TYPE among scalar conversions. * c-tree.h (null_pointer_constant_p): Declare. gcc/testsuite/ * gcc.dg/c2x-nullptr-1.c: Test conversion of null pointer constants to nullptr_t. * gcc.dg/c2x-nullptr-3.c: Do not expect errors for conversion of null pointer constants to nullptr_t. Do test errors for conversion of other values to nullptr_t and for unary '+' on nullptr_t.
-rw-r--r--gcc/c/c-convert.cc21
-rw-r--r--gcc/c/c-tree.h1
-rw-r--r--gcc/c/c-typeck.cc7
-rw-r--r--gcc/testsuite/gcc.dg/c2x-nullptr-1.c16
-rw-r--r--gcc/testsuite/gcc.dg/c2x-nullptr-3.c19
5 files changed, 48 insertions, 16 deletions
diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc
index dccd245..0f35dc4 100644
--- a/gcc/c/c-convert.cc
+++ b/gcc/c/c-convert.cc
@@ -157,6 +157,19 @@ c_convert (tree type, tree expr, bool init_const)
ret = convert_to_pointer (type, e);
goto maybe_fold;
+ case NULLPTR_TYPE:
+ /* A null pointer constant or value of type nullptr_t may be
+ converted to nullptr_t. The latter case has already been
+ handled. build_c_cast will create an additional NOP_EXPR to
+ ensure the result of the conversion is not itself a null
+ pointer constant. */
+ if (null_pointer_constant_p (expr))
+ {
+ ret = build_int_cst (type, 0);
+ goto maybe_fold;
+ }
+ break;
+
case REAL_TYPE:
ret = convert_to_real (type, e);
goto maybe_fold;
@@ -201,12 +214,14 @@ c_convert (tree type, tree expr, bool init_const)
}
/* If we are converting to nullptr_t, don't say "non-scalar type" because
- the nullptr_t type is a scalar type. Only nullptr_t shall be converted
- to nullptr_t. */
+ the nullptr_t type is a scalar type. Only nullptr_t or a null pointer
+ constant shall be converted to nullptr_t. */
if (code == NULLPTR_TYPE)
{
error ("conversion from %qT to %qT", TREE_TYPE (e), type);
- inform (input_location, "only %qT can be converted to %qT", type, type);
+ inform (input_location,
+ "only %qT or a null pointer constant can be converted to %qT",
+ type, type);
}
else
error ("conversion to non-scalar type requested");
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 00ccf87..e5eefe6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -728,6 +728,7 @@ extern location_t c_last_sizeof_loc;
extern struct c_switch *c_switch_stack;
+extern bool null_pointer_constant_p (const_tree);
extern bool char_type_p (tree);
extern tree c_objc_common_truthvalue_conversion (location_t, tree);
extern tree require_complete_type (location_t, tree);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 157b77e..e37b097 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -89,7 +89,6 @@ static bool require_constant_value;
static bool require_constant_elements;
static bool require_constexpr_value;
-static bool null_pointer_constant_p (const_tree);
static tree qualify_type (tree, tree);
static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
bool *);
@@ -130,7 +129,7 @@ static int comptypes_internal (const_tree, const_tree, bool *, bool *);
/* Return true if EXP is a null pointer constant, false otherwise. */
-static bool
+bool
null_pointer_constant_p (const_tree expr)
{
/* This should really operate on c_expr structures, but they aren't
@@ -7837,6 +7836,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
in_late_binary_op = save;
return ret;
}
+ else if (codel == NULLPTR_TYPE && null_pointer_constant)
+ return convert (type, rhs);
switch (errtype)
{
@@ -8596,7 +8597,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE
|| code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE
- || code == COMPLEX_TYPE || code == VECTOR_TYPE)
+ || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE)
{
tree unconverted_init = inside_init;
if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
diff --git a/gcc/testsuite/gcc.dg/c2x-nullptr-1.c b/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
index 04f9901..4e44023 100644
--- a/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
+++ b/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
@@ -11,8 +11,9 @@ void f2 (int *) { }
void f3 (_Bool) { }
nullptr_t cmp (void) { return nullptr; }
-/* The type nullptr_t shall not be converted to any type other than void, bool or
- a pointer type. No type other than nullptr_t shall be converted to nullptr_t. */
+/* The type nullptr_t shall not be converted to any type other than void, bool
+ or a pointer type. No type other than nullptr_t or a null pointer constant
+ shall be converted to nullptr_t. */
void
test1 (void)
{
@@ -63,6 +64,17 @@ test1 (void)
(void) np2;
(void) cmp ();
(void)(nullptr_t) nullptr;
+
+ const nullptr_t n = 0;
+ (void) (nullptr_t) 0;
+
+ f1 (0);
+ f1 ((void *) 0);
+ f1 (0L);
+ nullptr_t n2;
+ n2 = (void *) 0;
+ n2 = 123 - 123;
+ (void) n2;
}
/* Test valid comparison. */
diff --git a/gcc/testsuite/gcc.dg/c2x-nullptr-3.c b/gcc/testsuite/gcc.dg/c2x-nullptr-3.c
index 591ab7e..09d9856 100644
--- a/gcc/testsuite/gcc.dg/c2x-nullptr-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-nullptr-3.c
@@ -29,21 +29,24 @@ test2 (void)
float d = nullptr; /* { dg-error "incompatible types" } */
char arr[10] = { nullptr }; /* { dg-error "incompatible types" } */
- /* No type other than nullptr_t shall be converted to nullptr_t. */
- const nullptr_t n = 0; /* { dg-error "invalid initializer" } */
- +(nullptr_t) 0; /* { dg-error "conversion from .int. to .nullptr_t." } */
-
- g (0); /* { dg-error "incompatible type" } */
+ /* Unary '+' is not valid for nullptr. */
+ +nullptr; /* { dg-error "wrong type argument to unary plus" } */
+ g (0.0); /* { dg-error "incompatible type" } */
+ g (1); /* { dg-error "incompatible type" } */
+ g ((int) (float) 0.0); /* { dg-error "incompatible type" } */
int i = 42 + nullptr; /* { dg-error "invalid operands" } */
/* The assignment of an object of type nullptr_t with a value of another
- type, even if the value is a null pointer constant, is a constraint
+ type, other than a null pointer constant, is a constraint
violation. */
nullptr_t m;
- m = 0; /* { dg-error "incompatible types" } */
+ m = 1; /* { dg-error "incompatible types" } */
+ m = 0.0; /* { dg-error "incompatible types" } */
(void) m;
- nullptr_t o = 0; /* { dg-error "invalid initializer" } */
+ nullptr_t o = 1; /* { dg-error "incompatible types" } */
+ (nullptr_t) 0.0; /* { dg-error "conversion" } */
+ (nullptr_t) (int) (float) 0.0; /* { dg-error "conversion" } */
switch (nullptr); /* { dg-error "switch quantity not an integer" } */
}