re PR c++/67104 (Constant expression factory function initializes std::array with...
authorJason Merrill <jason@redhat.com>
Wed, 12 Aug 2015 18:02:43 +0000 (14:02 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 12 Aug 2015 18:02:43 +0000 (14:02 -0400)
PR c++/67104
* constexpr.c (cxx_eval_array_reference): Handle sparse
CONSTRUCTORs.

From-SVN: r226830

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

index 4f3f46dda344362c7dd1e7c585199067f0dc7751..07ed20ff628fe4dc6ae824074de6a0de5dfb117a 100644 (file)
@@ -1,5 +1,9 @@
 2015-08-12  Jason Merrill  <jason@redhat.com>
 
+       PR c++/67104
+       * constexpr.c (cxx_eval_array_reference): Handle sparse
+       CONSTRUCTORs.
+
        PR c++/67108
        * decl2.c (c_parse_final_cleanups): Set at_eof to 2 at end.
        * error.c (dump_template_bindings): Don't tsubst in that case.
index 218faeccf80221ceedb5408954a58eb07c5ae10d..b6788c7a7c0a2a9e146ac92e21b3dd9234860199 100644 (file)
@@ -1697,7 +1697,38 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
       VERIFY_CONSTANT (ary);
       gcc_unreachable ();
     }
-  if (compare_tree_int (index, len) >= 0)
+
+  i = tree_to_shwi (index);
+  bool found = true;
+  if (TREE_CODE (ary) == CONSTRUCTOR && len
+      && (TREE_CODE (CONSTRUCTOR_ELT (ary, len-1)->index) == RANGE_EXPR
+         || compare_tree_int (CONSTRUCTOR_ELT (ary, len-1)->index, len-1)))
+    {
+      /* The last element doesn't match its position in the array; this must be
+        a sparse array from cxx_eval_store_expression.  So iterate.  */
+      found = false;
+      vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (ary);
+      constructor_elt *e;
+      for (unsigned ix = 0; vec_safe_iterate (v, ix, &e); ++i)
+       {
+         if (TREE_CODE (e->index) == RANGE_EXPR)
+           {
+             tree lo = TREE_OPERAND (e->index, 0);
+             tree hi = TREE_OPERAND (e->index, 1);
+             if (tree_int_cst_le (lo, index) && tree_int_cst_le (index, hi))
+               found = true;
+           }
+         else if (tree_int_cst_equal (e->index, index))
+           found = true;
+         if (found)
+           {
+             i = ix;
+             break;
+           }
+       }
+    }
+
+  if (i >= len || !found)
     {
       if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary))))
        {
@@ -1714,14 +1745,14 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
       *non_constant_p = true;
       return t;
     }
-  else if (tree_int_cst_lt (index, integer_zero_node))
+  else if (i < 0)
     {
       if (!ctx->quiet)
        error ("negative array subscript");
       *non_constant_p = true;
       return t;
     }
-  i = tree_to_shwi (index);
+
   if (TREE_CODE (ary) == CONSTRUCTOR)
     return (*CONSTRUCTOR_ELTS (ary))[i].value;
   else if (elem_nchars == 1)
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-array1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-array1.C
new file mode 100644 (file)
index 0000000..efe4617
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/67104
+// { dg-do compile { target c++14 } }
+
+template <typename T, int N> struct array
+{
+  constexpr T &operator[](int index) { return data[index]; }
+  constexpr T operator[](int index) const { return data[index]; }
+  T data[N];
+};
+
+constexpr array<long unsigned, 1001>
+make_bottle_count ()
+{
+  array<long unsigned, 1001> a{};
+  a[65] = 1;
+  return a;
+}
+
+constexpr auto bottle_count = make_bottle_count ();
+static_assert (bottle_count[65], "");