[C++ PATCH] Fix constexpr handling of arrays with unknown bound (PR c++/83993)

Jakub Jelinek jakub@redhat.com
Wed Jan 24 23:50:00 GMT 2018


Hi!

In constexpr evaluation of array references for arrays with unknown bounds,
we need to diagnose out of bounds accesses, but really don't know the bounds
at compile time, right now GCC will see nelts as error_mark_node + 1 and
will not consider them a constant expression at all.
>From the clang commit message it seems that CWG is leaning towards allowing
&array_with_unknown_bound[0] and array_with_unknown_bound, but disallowing
any other indexes (i.e. assume the array could have zero elements).
The following patch implements that.  Bootstrapped/regtested on x86_64-linux
and i686-linux, ok for trunk?

2018-01-24  Jakub Jelinek  <jakub@redhat.com>

	PR c++/83993
	* constexpr.c (diag_array_subscript): Emit different diagnostics
	if TYPE_DOMAIN (arraytype) is NULL.
	(cxx_eval_array_reference, cxx_eval_store_expression): For arrays
	with NULL TYPE_DOMAIN use size_zero_node as nelts.

	* g++.dg/init/pr83993-1.C: New test.
	* g++.dg/cpp0x/pr83993.C: New test.

--- gcc/cp/constexpr.c.jj	2018-01-19 23:34:04.897278768 +0100
+++ gcc/cp/constexpr.c	2018-01-24 13:38:40.572913190 +0100
@@ -2270,13 +2270,20 @@ diag_array_subscript (const constexpr_ct
       tree sidx = fold_convert (ssizetype, index);
       if (DECL_P (array))
 	{
-	  error ("array subscript value %qE is outside the bounds "
-		 "of array %qD of type %qT", sidx, array, arraytype);
+	  if (TYPE_DOMAIN (arraytype))
+	    error ("array subscript value %qE is outside the bounds "
+	           "of array %qD of type %qT", sidx, array, arraytype);
+	  else
+	    error ("array subscript value %qE used on array %qD of "
+		   "type %qT with unknown bounds", sidx, array, arraytype);
 	  inform (DECL_SOURCE_LOCATION (array), "declared here");
 	}
-      else
+      else if (TYPE_DOMAIN (arraytype))
 	error ("array subscript value %qE is outside the bounds "
 	       "of array type %qT", sidx, arraytype);
+      else
+	error ("array subscript value %qE used on array of type %qT "
+	       "with unknown bounds", sidx, arraytype);
     }
 }
 
@@ -2361,7 +2368,12 @@ cxx_eval_array_reference (const constexp
 
   tree nelts;
   if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE)
-    nelts = array_type_nelts_top (TREE_TYPE (ary));
+    {
+      if (TYPE_DOMAIN (TREE_TYPE (ary)))
+	nelts = array_type_nelts_top (TREE_TYPE (ary));
+      else
+	nelts = size_zero_node;
+    }
   else if (VECTOR_TYPE_P (TREE_TYPE (ary)))
     nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary)));
   else
@@ -3439,7 +3451,12 @@ cxx_eval_store_expression (const constex
 	  tree nelts, ary;
 	  ary = TREE_OPERAND (probe, 0);
 	  if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE)
-	    nelts = array_type_nelts_top (TREE_TYPE (ary));
+	    {
+	      if (TYPE_DOMAIN (TREE_TYPE (ary)))
+		nelts = array_type_nelts_top (TREE_TYPE (ary));
+	      else
+		nelts = size_zero_node;
+	    }
 	  else if (VECTOR_TYPE_P (TREE_TYPE (ary)))
 	    nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary)));
 	  else
--- gcc/testsuite/g++.dg/init/pr83993-1.C.jj	2018-01-24 13:45:43.430864528 +0100
+++ gcc/testsuite/g++.dg/init/pr83993-1.C	2018-01-24 13:44:59.352869530 +0100
@@ -0,0 +1,11 @@
+// PR c++/83993
+// { dg-do compile }
+
+extern const int a[];
+const int *const b = &a[0];
+
+int
+foo ()
+{
+  return b[0];
+}
--- gcc/testsuite/g++.dg/cpp0x/pr83993.C.jj	2018-01-24 14:09:01.846716177 +0100
+++ gcc/testsuite/g++.dg/cpp0x/pr83993.C	2018-01-24 14:08:41.246718212 +0100
@@ -0,0 +1,49 @@
+// PR c++/83993
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern const int a[];
+const int b[5] = { 1, 2, 3, 4, 5 };
+extern const int c[4];
+constexpr const int *d = &a[0];
+constexpr const int *d2 = a;
+constexpr const int *e = &a[1];		// { dg-error "array subscript value '1' used on array 'a' of type 'const int \\\[\\\]' with unknown bounds" }
+constexpr const int *f = &b[0];
+constexpr const int *f2 = b;
+constexpr const int *g = &b[5];
+constexpr const int *h = &b[6];		// { dg-error "array subscript value '6' is outside the bounds of array 'b' of type 'const int \\\[5\\\]'" }
+constexpr const int *i = &c[0];
+constexpr const int *i2 = c;
+constexpr const int *j = &c[4];
+constexpr const int *k = &c[5];		// { dg-error "array subscript value '5' is outside the bounds of array 'c' of type 'const int \\\[4\\\]'" }
+extern const int l[];
+
+void
+foo ()
+{
+  extern const int l[3];
+  constexpr const int *m = &l[0];
+  constexpr const int *m2 = l;
+  constexpr const int *n = &l[1];
+  static_assert (m == m2, "");
+}
+
+constexpr const int *m = &l[0];
+constexpr const int *m2 = l;
+constexpr const int *n = &l[1];		// { dg-error "array subscript value '1' used on array 'l' of type 'const int \\\[\\\]' with unknown bounds" }
+static_assert (d == d2 && f == f2 && i == i2 && m == m2, "");
+const int o[] = { 1, 2 };
+constexpr const int *p = &o[0];
+constexpr const int *p2 = o;
+constexpr const int *q = &o[2];
+constexpr const int *r = &o[3];		// { dg-error "array subscript value '3' is outside the bounds of array 'o' of type 'const int \\\[2\\\]'" }
+struct S { char a; char b[]; } s;
+constexpr const char *t = &s.b[0];
+constexpr const char *t2 = s.b;
+constexpr const char *u = &s.b[1];	// { dg-error "array subscript value '1' used on array of type 'char \\\[\\\]' with unknown bounds" }
+struct V { int a; };
+extern V v[];
+constexpr V *w = &v[0];
+constexpr V *w2 = v;
+constexpr int *x = &v[0].a;
+constexpr int y = a[0];			// { dg-error "the value of 'a' is not usable in a constant expression" }

	Jakub



More information about the Gcc-patches mailing list