re PR c++/77830 (internal compiler error: in output_constructor_regular_field, at...
authorJakub Jelinek <jakub@redhat.com>
Wed, 21 Dec 2016 21:58:23 +0000 (22:58 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 21 Dec 2016 21:58:23 +0000 (22:58 +0100)
PR c++/77830
* constexpr.c (cxx_eval_array_reference): Perform out of bounds
verification even if lval is true, just allow one past the last
element in that case.
(cxx_eval_store_expression): Detect stores to out of bound
ARRAY_REF.

* g++.dg/cpp1y/pr77830.C: New test.
* g++.dg/cpp0x/pr65398.C: Adjust expected diagnostics.

From-SVN: r243873

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/pr65398.C
gcc/testsuite/g++.dg/cpp1y/pr77830.C [new file with mode: 0644]

index db3582a..180a0fb 100644 (file)
@@ -1,3 +1,12 @@
+2016-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/77830
+       * constexpr.c (cxx_eval_array_reference): Perform out of bounds
+       verification even if lval is true, just allow one past the last
+       element in that case.
+       (cxx_eval_store_expression): Detect stores to out of bound
+       ARRAY_REF.
+
 2016-12-21  Jason Merrill  <jason@redhat.com>
 
        Implement P0522R0, matching of template template arguments.
index aedd004..ca259cb 100644 (file)
@@ -2183,9 +2183,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
                                           lval,
                                           non_constant_p, overflow_p);
   tree index, oldidx;
-  HOST_WIDE_INT i;
-  tree elem_type;
-  unsigned len, elem_nchars = 1;
+  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);
@@ -2193,39 +2193,38 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
                                        false,
                                        non_constant_p, overflow_p);
   VERIFY_CONSTANT (index);
-  if (lval && ary == oldary && index == oldidx)
-    return t;
-  else if (lval)
-    return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
-  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)
+  if (!lval)
     {
-      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)
-    len = VECTOR_CST_NELTS (ary);
-  else
-    {
-      /* We can't do anything with other tree codes, so use
-        VERIFY_CONSTANT to complain and fail.  */
-      VERIFY_CONSTANT (ary);
-      gcc_unreachable ();
-    }
+      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)
+       len = VECTOR_CST_NELTS (ary);
+      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_fits_shwi_p (index)
-      || (i = tree_to_shwi (index)) < 0)
-    {
-      diag_array_subscript (ctx, ary, index);
-      *non_constant_p = true;
-      return t;
+      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;
@@ -2240,13 +2239,20 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
   nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
                                        overflow_p);
   VERIFY_CONSTANT (nelts);
-  if (!tree_int_cst_lt (index, nelts))
+  if (lval
+      ? !tree_int_cst_le (index, nelts)
+      : !tree_int_cst_lt (index, nelts))
     {
       diag_array_subscript (ctx, ary, index);
       *non_constant_p = true;
       return t;
     }
 
+  if (lval && ary == oldary && index == oldidx)
+    return t;
+  else if (lval)
+    return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
+
   bool found;
   if (TREE_CODE (ary) == CONSTRUCTOR)
     {
@@ -3281,6 +3287,47 @@ 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);
+         if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE)
+           nelts = array_type_nelts_top (TREE_TYPE (ary));
+         else if (VECTOR_TYPE_P (TREE_TYPE (ary)))
+           nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary)));
+         else
+           gcc_unreachable ();
+         nelts = cxx_eval_constant_expression (ctx, nelts, false,
+                                               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::eq_p (TREE_OPERAND (probe, 1), 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
index e6ee770..2da0d44 100644 (file)
@@ -1,3 +1,9 @@
+2016-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/77830
+       * g++.dg/cpp1y/pr77830.C: New test.
+       * g++.dg/cpp0x/pr65398.C: Adjust expected diagnostics.
+
 2016-12-21  Bernd Schmidt  <bschmidt@redhat.com>
 
        PR target/71321
index 6bd34a4..bab875c 100644 (file)
@@ -20,9 +20,9 @@ constexpr char d5 = *(&s[4] - 4);
 constexpr char d6 = *(&s[4] - 5);  // { dg-error "array subscript" }
 
 /* Don't accept invalid stuff.  */
-constexpr char e1 = *(&s[5] - 1); // { dg-error "is not a constant expression" }
-constexpr char e2 = *(&s[5] - 2); // { dg-error "is not a constant expression" }
-constexpr char e3 = *(&s[5] - 3); // { dg-error "is not a constant expression" }
+constexpr char e1 = *(&s[5] - 1); // { dg-error "array subscript" }
+constexpr char e2 = *(&s[5] - 2); // { dg-error "array subscript" }
+constexpr char e3 = *(&s[5] - 3); // { dg-error "array subscript" }
 
 SA (c1 == 'a');
 SA (c2 == 'b');
@@ -53,9 +53,9 @@ constexpr char j5 = *(&l[4] - 4);
 constexpr char j6 = *(&l[4] - 5);  // { dg-error "array subscript" }
 
 /* Don't accept invalid stuff.  */
-constexpr char k1 = *(&l[5] - 1); // { dg-error "is not a constant expression" }
-constexpr char k2 = *(&l[5] - 2); // { dg-error "is not a constant expression" }
-constexpr char k3 = *(&l[5] - 3); // { dg-error "is not a constant expression" }
+constexpr char k1 = *(&l[5] - 1); // { dg-error "array subscript" }
+constexpr char k2 = *(&l[5] - 2); // { dg-error "array subscript" }
+constexpr char k3 = *(&l[5] - 3); // { dg-error "array subscript" }
 
 SA (i1 == 'c');
 SA (i2 == 'd');
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr77830.C b/gcc/testsuite/g++.dg/cpp1y/pr77830.C
new file mode 100644 (file)
index 0000000..9235b40
--- /dev/null
@@ -0,0 +1,34 @@
+// PR c++/77830
+// { dg-do compile { target c++14 } }
+
+template <int N>
+struct P
+{
+  char arr[N][1];
+  constexpr void foo (const char *, int);
+};
+
+template <int N>
+constexpr void
+P<N>::foo (const char *, int i)
+{
+  for (auto j = 0; j < 2; ++j)
+    arr[i][j] = true;
+}
+
+template <typename... T>
+constexpr auto
+bar (T... a)
+{
+  const char *s[]{a...};
+  P<sizeof...(a)> p{};
+  for (auto i = 0; i < sizeof...(a); ++i)
+    p.foo (s[i], i);
+  return p;
+}
+
+int
+main ()
+{
+  constexpr auto a = bar ("", "");     // { dg-error "outside the bounds of array type" }
+}