c: Update checks on constexpr pointer initializers
authorJoseph Myers <joseph@codesourcery.com>
Wed, 8 Feb 2023 23:41:47 +0000 (23:41 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Wed, 8 Feb 2023 23:41:47 +0000 (23:41 +0000)
WG14 has agreed a change of the rules on constexpr pointer
initializers, so that a (constant) null value that is not a null
pointer constant is accepted in that context, rather than only
accepting null pointer constants.  (In particular, this means that a
constexpr variable of pointer type can be used to initializer another
such variable.)  Remove the null pointer constant restriction in GCC,
instead checking just whether the value is null.

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

gcc/c/
* c-typeck.cc (check_constexpr_init): Remove argument
null_pointer_constant.  Only check pointer initializers for being
null.
(digest_init): Update calls to check_constexpr_init.

gcc/testsuite/
* gcc.dg/c2x-constexpr-1.c: Test initialization of constexpr
pointers with null values that are not null pointer constants.
* gcc.dg/c2x-constexpr-3.c: Test initialization of constexpr
pointers with non-null values, not with null values that are not
null pointer constants.

gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/c2x-constexpr-1.c
gcc/testsuite/gcc.dg/c2x-constexpr-3.c

index 224a9cb..157b77e 100644 (file)
@@ -8186,23 +8186,20 @@ constexpr_init_fits_real_type (tree type, tree init)
 
 /* Check whether INIT (location LOC) is valid as a 'constexpr'
    initializer for type TYPE, and give an error if not.  INIT has
-   already been folded and verified to be constant.
-   NULL_POINTER_CONSTANT, INT_CONST_EXPR and ARITH_CONST_EXPR say
-   whether it is a null pointer constant, integer constant expression
-   or arithmetic constant expression, respectively.  If TYPE is not a
-   scalar type, this function does nothing.  */
+   already been folded and verified to be constant.  INT_CONST_EXPR
+   and ARITH_CONST_EXPR say whether it is an integer constant
+   expression or arithmetic constant expression, respectively.  If
+   TYPE is not a scalar type, this function does nothing.  */
 
 static void
 check_constexpr_init (location_t loc, tree type, tree init,
-                     bool null_pointer_constant, bool int_const_expr,
-                     bool arith_const_expr)
+                     bool int_const_expr, bool arith_const_expr)
 {
   if (POINTER_TYPE_P (type))
     {
-      /* The initializer must be a null pointer constant.  */
-      if (!null_pointer_constant)
-       error_at (loc, "%<constexpr%> pointer initializer is not a "
-                 "null pointer constant");
+      /* The initializer must be null.  */
+      if (TREE_CODE (init) != INTEGER_CST || !integer_zerop (init))
+       error_at (loc, "%<constexpr%> pointer initializer is not null");
       return;
     }
   if (INTEGRAL_TYPE_P (type))
@@ -8582,8 +8579,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
                      "initializer element is not a constant expression");
       else if (require_constexpr)
        check_constexpr_init (init_loc, type, inside_init,
-                             null_pointer_constant, int_const_expr,
-                             arith_const_expr);
+                             int_const_expr, arith_const_expr);
 
       /* Added to enable additional -Wsuggest-attribute=format warnings.  */
       if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
@@ -8638,8 +8634,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
                      "initializer element is not a constant expression");
       else if (require_constexpr)
        check_constexpr_init (init_loc, type, unconverted_init,
-                             null_pointer_constant, int_const_expr,
-                             arith_const_expr);
+                             int_const_expr, arith_const_expr);
 
       return inside_init;
     }
index 97b54f1..8989530 100644 (file)
@@ -176,6 +176,12 @@ constexpr int v97[100] = { [v82.x.f] = 7 };
 static int v98[v94];
 constexpr _Complex double v99 = 1.0;
 constexpr _Complex float v100 = 12345;
+constexpr int *v101 = (int *) 0;
+constexpr void *v102 = (void *) (void *) 0;
+constexpr void *v103 = v101;
+constexpr void *v104 = v84;
+struct s105 { void *p; };
+constexpr struct s105 v106 = { (int *) 0 };
 
 void
 f0 ()
@@ -251,6 +257,11 @@ f0 ()
   (constexpr union u58) { { 0 } }; /* { dg-warning "braces around scalar initializer" } */
   (constexpr _Complex double) { 1.0 };
   (constexpr _Complex float) { 12345 };
+  (constexpr int *) { (int *) 0 };
+  (constexpr void *) { (void *) (void *) 0 };
+  (constexpr void *) { v101 };
+  (constexpr void *) { v84 };
+  (constexpr struct s105) { (int *) 0 };
   /* It's not entirely clear if constexpr declarations are allowed in this
      position in a for loop; presume they are, as implicitly auto just as if no
      storage class specifiers were used.  */
index 44a3ed3..b9b780e 100644 (file)
@@ -102,12 +102,12 @@ struct s85 { int a; } constexpr v85 = { 0 }; /* { dg-error "'struct s85' defined
 union u86 { int a; } constexpr v86 = { 0 }; /* { dg-error "'union u86' defined in underspecified object declaration" } */
 enum e87 { E87 } constexpr v87 = E87; /* { dg-error "'enum e87' defined in underspecified object declaration" } */
 enum { E88 } constexpr v88 = E88; /* { dg-error "defined in underspecified object declaration" } */
-constexpr int *v89 = (int *) 0; /* { dg-error "'constexpr' pointer initializer is not a null pointer constant" } */
-constexpr void *v90 = (void *) (void *) 0; /* { dg-error "'constexpr' pointer initializer is not a null pointer constant" } */
+constexpr void *v89 = (void *) 64; /* { dg-error "'constexpr' pointer initializer is not null" } */
+constexpr int *v90 = (int *) 64; /* { dg-error "'constexpr' pointer initializer is not null" } */
 constexpr int v91 = (int) (double) 1.0; /* { dg-error "constexpr' integer initializer is not an integer constant expression" } */
 constexpr struct s71 v92 = { (int) (double) 1.0, 0 }; /* { dg-error "constexpr' integer initializer is not an integer constant expression" } */
 struct s93 { void *p; };
-constexpr struct s93 v94 = { (int *) 0 }; /* { dg-error "'constexpr' pointer initializer is not a null pointer constant" } */
+constexpr struct s93 v94 = { (int *) 16 }; /* { dg-error "'constexpr' pointer initializer is not null" } */
 constexpr int v95 = (unsigned int) -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr unsigned char v96 = -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr signed char v97 = 1234567LL; /* { dg-error "'constexpr' initializer not representable in type of object" } */
@@ -200,11 +200,11 @@ f0 ()
   (constexpr union fs13 { int a; }) { 0 }; /* { dg-error "defined in 'constexpr' compound literal" } */
   (constexpr enum fs14 { FS14 }) { FS14 }; /* { dg-error "defined in 'constexpr' compound literal" } */
   (constexpr enum { FS15 }) { FS15 }; /* { dg-error "defined in 'constexpr' compound literal" } */
-  (constexpr int *) { (int *) 0 }; /* { dg-error "'constexpr' pointer initializer is not a null pointer constant" } */
-  (constexpr void *) { (void *) (void *) 0 }; /* { dg-error "'constexpr' pointer initializer is not a null pointer constant" } */
+  (constexpr void *) { (void *) 64 }; /* { dg-error "'constexpr' pointer initializer is not null" } */
+  (constexpr int *) { (int *) 64 }; /* { dg-error "'constexpr' pointer initializer is not null" } */
   (constexpr int) { (int) (double) 1.0 }; /* { dg-error "constexpr' integer initializer is not an integer constant expression" } */
   (constexpr struct s71) { (int) (double) 1.0, 0 }; /* { dg-error "constexpr' integer initializer is not an integer constant expression" } */
-  (constexpr struct s93) { (int *) 0 }; /* { dg-error "'constexpr' pointer initializer is not a null pointer constant" } */
+  (constexpr struct s93) { (int *) 16 }; /* { dg-error "'constexpr' pointer initializer is not null" } */
   (constexpr int) { (unsigned int) -1 }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr unsigned char) { -1 }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr signed char) { 1234567LL }; /* { dg-error "'constexpr' initializer not representable in type of object" } */