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

Martin Sebor msebor@gmail.com
Thu Jan 25 20:23:00 GMT 2018


On 01/24/2018 04:19 PM, Jakub Jelinek wrote:
> 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?

Unless your goal is to have GCC 8 reject just some subset of
expressions in the reported test case (and fix the rest in
the future) then there still are other potentially invalid
expressions that GCC will continue to accept.  For example,
the initialization of p in f() is rejected with the patch but
the use of the same expression in g() is still accepted (Clang
silently accepts both).  It could be due to the same problem
as bug 82877.  Other similar issues are being tracked in bug
82876 and 82874.

   extern const int a[];

   constexpr int f ()
   {
     const int *p = &a[7], *q = &a[0];
     return p - q;
   }

   constexpr int g ()
   {
     return &a[7] - &a[0];
   }

   constexpr const int i = f ();
   constexpr const int j = g ();

Regarding the patch, just a couple of minor nits:

The consensus we have reached some time back was not to quote
integer constants so I would suggest to follow it in new code
and take the opportunity to remove the quoting from surrounding
code.

   https://gcc.gnu.org/wiki/DiagnosticsGuidelines#Quoting

In addition, I would suggest to phrase the error as "array
subscript value %E is used *with* array qD" as opposed to
"on array."  If we wanted to make it clearer that it's
the fact that the index is non-zero is the problem mentioning
it in the warning might help ("non-zero array subscript %E...")

Alternatively, since the bounds are unknown is evident from
the type of the array (e.g., "int[]") just: "array subscript
value %E may be outside the bounds of array %qD of type %qT"
might be good enough.

Martin

>
> 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