Consolidate constexpr array handling.
authorJason Merrill <jason@redhat.com>
Tue, 18 Jun 2019 16:08:23 +0000 (12:08 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 18 Jun 2019 16:08:23 +0000 (12:08 -0400)
* constexpr.c (eval_and_check_array_index): Split out from...
(cxx_eval_array_reference): ...here.
(cxx_eval_store_expression): Use it here, too.
(diag_array_subscript): Take location.  Strip location wrapper.

From-SVN: r272430

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/cpp1y/constexpr-79655.C
gcc/testsuite/g++.dg/cpp1y/pr77830.C
gcc/testsuite/g++.dg/ext/constexpr-vla1.C

index 4f26dc3423f154d2c6f86f983abdd9820c832c7c..1071a52a5586f22fdbe7b1b554d2dc7bbf7fb6b2 100644 (file)
@@ -1,3 +1,10 @@
+2019-06-18  Jason Merrill  <jason@redhat.com>
+
+       * constexpr.c (eval_and_check_array_index): Split out from...
+       (cxx_eval_array_reference): ...here.
+       (cxx_eval_store_expression): Use it here, too.
+       (diag_array_subscript): Take location.  Strip location wrapper.
+
 2019-06-18  Jason Merrill  <jason@redhat.com>
 
        * constexpr.c (cxx_eval_constant_expression): Handle conversion from
index 0f68a0c9fcac73ba1b6a479336ee0f35da8d009a..7c733d78b5b6a7ef5d3a5c6a0eae8838d3144f92 100644 (file)
@@ -2488,7 +2488,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert)
    an out-of-bounds subscript INDEX into the expression ARRAY.  */
 
 static void
-diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index)
+diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array, tree index)
 {
   if (!ctx->quiet)
     {
@@ -2497,22 +2497,23 @@ diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index)
       /* Convert the unsigned array subscript to a signed integer to avoid
         printing huge numbers for small negative values.  */
       tree sidx = fold_convert (ssizetype, index);
+      STRIP_ANY_LOCATION_WRAPPER (array);
       if (DECL_P (array))
        {
          if (TYPE_DOMAIN (arraytype))
-           error ("array subscript value %qE is outside the bounds "
-                  "of array %qD of type %qT", sidx, array, arraytype);
+           error_at (loc, "array subscript value %qE is outside the bounds "
+                     "of array %qD of type %qT", sidx, array, arraytype);
          else
-           error ("nonzero array subscript %qE is used with array %qD of "
-                  "type %qT with unknown bounds", sidx, array, arraytype);
+           error_at (loc, "nonzero array subscript %qE is used with array %qD of "
+                     "type %qT with unknown bounds", sidx, array, arraytype);
          inform (DECL_SOURCE_LOCATION (array), "declared here");
        }
       else if (TYPE_DOMAIN (arraytype))
-       error ("array subscript value %qE is outside the bounds "
-              "of array type %qT", sidx, arraytype);
+       error_at (loc, "array subscript value %qE is outside the bounds "
+                 "of array type %qT", sidx, arraytype);
       else
-       error ("nonzero array subscript %qE is used with array of type %qT "
-              "with unknown bounds", sidx, arraytype);
+       error_at (loc, "nonzero array subscript %qE is used with array of type %qT "
+                 "with unknown bounds", sidx, arraytype);
     }
 }
 
@@ -2563,6 +2564,44 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
   return r;
 }
 
+/* Subroutine of cxx_eval_array_reference.  T is an ARRAY_REF; evaluate the
+   subscript, diagnose any problems with it, and return the result.  */
+
+static tree
+eval_and_check_array_index (const constexpr_ctx *ctx,
+                           tree t, bool allow_one_past,
+                           bool *non_constant_p, bool *overflow_p)
+{
+  location_t loc = cp_expr_loc_or_loc (t, input_location);
+  tree ary = TREE_OPERAND (t, 0);
+  t = TREE_OPERAND (t, 1);
+  tree index = cxx_eval_constant_expression (ctx, t, false,
+                                            non_constant_p, overflow_p);
+  VERIFY_CONSTANT (index);
+
+  if (!tree_fits_shwi_p (index)
+      || tree_int_cst_sgn (index) < 0)
+    {
+      diag_array_subscript (loc, ctx, ary, index);
+      *non_constant_p = true;
+      return t;
+    }
+
+  tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
+                                         overflow_p);
+  VERIFY_CONSTANT (nelts);
+  if (allow_one_past
+      ? !tree_int_cst_le (index, nelts)
+      : !tree_int_cst_lt (index, nelts))
+    {
+      diag_array_subscript (loc, ctx, ary, index);
+      *non_constant_p = true;
+      return t;
+    }
+
+  return index;
+}
+
 /* Subroutine of cxx_eval_constant_expression.
    Attempt to reduce a reference to an array slot.  */
 
@@ -2575,71 +2614,47 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
   tree ary = cxx_eval_constant_expression (ctx, oldary,
                                           lval,
                                           non_constant_p, overflow_p);
-  tree index, oldidx;
-  HOST_WIDE_INT i = 0;
-  tree elem_type = NULL_TREE;
-  unsigned len = 0, elem_nchars = 1;
   if (*non_constant_p)
     return t;
-  oldidx = TREE_OPERAND (t, 1);
-  index = cxx_eval_constant_expression (ctx, oldidx,
-                                       false,
-                                       non_constant_p, overflow_p);
-  VERIFY_CONSTANT (index);
-  if (!lval)
-    {
-      elem_type = TREE_TYPE (TREE_TYPE (ary));
-      if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
-         && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
-         && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0))))
-       ary = TREE_OPERAND (ary, 0);
-      if (TREE_CODE (ary) == CONSTRUCTOR)
-       len = CONSTRUCTOR_NELTS (ary);
-      else if (TREE_CODE (ary) == STRING_CST)
-       {
-         elem_nchars = (TYPE_PRECISION (elem_type)
-                        / TYPE_PRECISION (char_type_node));
-         len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
-       }
-      else if (TREE_CODE (ary) == VECTOR_CST)
-       /* We don't create variable-length VECTOR_CSTs.  */
-       len = VECTOR_CST_NELTS (ary).to_constant ();
-      else
-       {
-         /* We can't do anything with other tree codes, so use
-            VERIFY_CONSTANT to complain and fail.  */
-         VERIFY_CONSTANT (ary);
-         gcc_unreachable ();
-       }
+  if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
+      && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
+      && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0))))
+    ary = TREE_OPERAND (ary, 0);
 
-      if (!tree_fits_shwi_p (index)
-         || (i = tree_to_shwi (index)) < 0)
-       {
-         diag_array_subscript (ctx, ary, index);
-         *non_constant_p = true;
-         return t;
-       }
-    }
-
-  tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
-                                         overflow_p);
-  VERIFY_CONSTANT (nelts);
-  if ((lval
-       ? !tree_int_cst_le (index, nelts)
-       : !tree_int_cst_lt (index, nelts))
-      || tree_int_cst_sgn (index) < 0)
-    {
-      diag_array_subscript (ctx, ary, index);
-      *non_constant_p = true;
-      return t;
-    }
+  tree oldidx = TREE_OPERAND (t, 1);
+  tree index = eval_and_check_array_index (ctx, t, lval,
+                                          non_constant_p, overflow_p);
+  if (*non_constant_p)
+    return t;
 
   if (lval && ary == oldary && index == oldidx)
     return t;
   else if (lval)
     return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
 
+  unsigned len = 0, elem_nchars = 1;
+  tree elem_type = TREE_TYPE (TREE_TYPE (ary));
+  if (TREE_CODE (ary) == CONSTRUCTOR)
+    len = CONSTRUCTOR_NELTS (ary);
+  else if (TREE_CODE (ary) == STRING_CST)
+    {
+      elem_nchars = (TYPE_PRECISION (elem_type)
+                    / TYPE_PRECISION (char_type_node));
+      len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
+    }
+  else if (TREE_CODE (ary) == VECTOR_CST)
+    /* We don't create variable-length VECTOR_CSTs.  */
+    len = VECTOR_CST_NELTS (ary).to_constant ();
+  else
+    {
+      /* We can't do anything with other tree codes, so use
+        VERIFY_CONSTANT to complain and fail.  */
+      VERIFY_CONSTANT (ary);
+      gcc_unreachable ();
+    }
+
   bool found;
+  HOST_WIDE_INT i = 0;
   if (TREE_CODE (ary) == CONSTRUCTOR)
     {
       HOST_WIDE_INT ix = find_array_ctor_elt (ary, index);
@@ -2648,7 +2663,10 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
        i = ix;
     }
   else
-    found = (i < len);
+    {
+      i = tree_to_shwi (index);
+      found = (i < len);
+    }
 
   if (found)
     {
@@ -3735,41 +3753,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
   if (*non_constant_p)
     return t;
 
-  /* cxx_eval_array_reference for lval = true allows references one past
-     end of array, because it does not know if it is just taking address
-     (which is valid), or actual dereference.  Here we know it is
-     a dereference, so diagnose it here.  */
-  for (tree probe = target; probe; )
-    {
-      switch (TREE_CODE (probe))
-       {
-       case ARRAY_REF:
-         tree nelts, ary;
-         ary = TREE_OPERAND (probe, 0);
-         nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary),
-                                            non_constant_p, overflow_p);
-         VERIFY_CONSTANT (nelts);
-         gcc_assert (TREE_CODE (nelts) == INTEGER_CST
-                     && TREE_CODE (TREE_OPERAND (probe, 1)) == INTEGER_CST);
-         if (wi::to_widest (TREE_OPERAND (probe, 1)) == wi::to_widest (nelts))
-           {
-             diag_array_subscript (ctx, ary, TREE_OPERAND (probe, 1));
-             *non_constant_p = true;
-             return t;
-           }
-         /* FALLTHRU */
-
-       case BIT_FIELD_REF:
-       case COMPONENT_REF:
-         probe = TREE_OPERAND (probe, 0);
-         continue;
-
-       default:
-         probe = NULL_TREE;
-         continue;
-       }
-    }
-
   if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (target), type))
     {
       /* For initialization of an empty base, the original target will be
@@ -3782,7 +3765,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
                                           non_constant_p, overflow_p);
     }
 
-  /* And then find the underlying variable.  */
+  /* Find the underlying variable.  */
   releasing_vec refs;
   tree object = NULL_TREE;
   for (tree probe = target; object == NULL_TREE; )
@@ -3792,9 +3775,20 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
        case BIT_FIELD_REF:
        case COMPONENT_REF:
        case ARRAY_REF:
-         vec_safe_push (refs, TREE_OPERAND (probe, 1));
-         vec_safe_push (refs, TREE_TYPE (probe));
-         probe = TREE_OPERAND (probe, 0);
+         {
+           tree ob = TREE_OPERAND (probe, 0);
+           tree elt = TREE_OPERAND (probe, 1);
+           if (TREE_CODE (probe) == ARRAY_REF)
+             {
+               elt = eval_and_check_array_index (ctx, probe, false,
+                                                 non_constant_p, overflow_p);
+               if (*non_constant_p)
+                 return t;
+             }
+           vec_safe_push (refs, elt);
+           vec_safe_push (refs, TREE_TYPE (probe));
+           probe = ob;
+         }
          break;
 
        default:
index cc9ce6c505ea5ee6fd29f40aae9c9496062c9ca4..063d556871d6f41cef8f429b587dba8f990519fc 100644 (file)
@@ -5,14 +5,14 @@ constexpr int
 foo (int x, int y)
 {
   int a[6] = { 1, 2, 3, 4, 5, 6 };
-  a[x] = 0;
-  return a[y];
+  a[x] = 0;                       // { dg-error "is outside the bounds" }
+  return a[y];                    // { dg-error "is outside the bounds" }
 }
 
-constexpr int b = foo (0, -1); // { dg-error "is outside the bounds|in .constexpr. expansion of " }
-constexpr int c = foo (0, 6);  // { dg-error "is outside the bounds|in .constexpr. expansion of " }
-constexpr int d = foo (6, 0);  // { dg-error "is outside the bounds|in .constexpr. expansion of " }
-constexpr int e = foo (-1, 0); // { dg-error "is outside the bounds|in .constexpr. expansion of " }
+constexpr int b = foo (0, -1); // { dg-message "in .constexpr. expansion of " }
+constexpr int c = foo (0, 6);  // { dg-message "in .constexpr. expansion of " }
+constexpr int d = foo (6, 0);  // { dg-message "in .constexpr. expansion of " }
+constexpr int e = foo (-1, 0); // { dg-message "in .constexpr. expansion of " }
 static_assert (foo (5, 5) == 0, "");
 static_assert (foo (4, 5) == 6, "");
 static_assert (foo (5, 4) == 5, "");
index 6fcb1ba8847049921e4b5184cec6c6a22d261f8e..21eeda3c940aa24538440a750e8e55a97a883edf 100644 (file)
@@ -13,7 +13,7 @@ constexpr void
 P<N>::foo (const char *, int i)
 {
   for (auto j = 0; j < 2; ++j)
-    arr[i][j] = true;
+    arr[i][j] = true;          // { dg-error "outside the bounds of array type" }
 }
 
 template <typename... T>
@@ -30,5 +30,5 @@ bar (T... a)
 int
 main ()
 {
-  constexpr auto a = bar ("", "");     // { dg-error "outside the bounds of array type|in .constexpr. expansion of " }
+  constexpr auto a = bar ("", "");     // { dg-message "in .constexpr. expansion of " }
 }
index aff1d21a4b7badbe288fd42576e93b13946e472b..62832725a59b8f2713f59257bf83196d9e6bbd4c 100644 (file)
@@ -21,10 +21,10 @@ fn_not_ok (int n)
     int z = 0;
 
     for (unsigned i = 0; i < sizeof (a); ++i)
-      z += a[i];
+      z += a[i];               // { dg-error "array subscript" }
 
     return z;
 }
 
 constexpr int n1 = fn_ok (3);
-constexpr int n2 = fn_not_ok (3); // { dg-error "array subscript|in .constexpr. expansion of " }
+constexpr int n2 = fn_not_ok (3); // { dg-message "in .constexpr. expansion of " }