re PR c++/89652 (ICE during constexpr evaluation)
authorJakub Jelinek <jakub@redhat.com>
Thu, 14 Mar 2019 08:13:09 +0000 (09:13 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 14 Mar 2019 08:13:09 +0000 (09:13 +0100)
PR c++/89652
* constexpr.c (struct constexpr_ctx): Change save_exprs type from
hash_set<tree> to vec<tree>.
(cxx_eval_call_expression): Adjust for save_exprs being a vec instead
of hash_set.
(cxx_eval_loop_expr): Likewise.  Truncate the vector after each
removal of SAVE_EXPRs from values.
(cxx_eval_constant_expression) <case SAVE_EXPR>: Call safe_push
method on save_exprs instead of add.

* g++.dg/cpp1y/constexpr-89652.C: New test.

From-SVN: r269671

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

index 1164652..7c0b4f4 100644 (file)
@@ -1,3 +1,15 @@
+2019-03-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/89652
+       * constexpr.c (struct constexpr_ctx): Change save_exprs type from
+       hash_set<tree> to vec<tree>.
+       (cxx_eval_call_expression): Adjust for save_exprs being a vec instead
+       of hash_set.
+       (cxx_eval_loop_expr): Likewise.  Truncate the vector after each
+       removal of SAVE_EXPRs from values.
+       (cxx_eval_constant_expression) <case SAVE_EXPR>: Call safe_push
+       method on save_exprs instead of add.
+
 2019-03-13  Jason Merrill  <jason@redhat.com>
 
        PR c++/86521 - C++17 copy elision in initialization by constructor.
index b2b575d..68e78d0 100644 (file)
@@ -1024,7 +1024,7 @@ struct constexpr_ctx {
   hash_map<tree,tree> *values;
   /* SAVE_EXPRs that we've seen within the current LOOP_EXPR.  NULL if we
      aren't inside a loop.  */
-  hash_set<tree> *save_exprs;
+  vec<tree> *save_exprs;
   /* The CONSTRUCTOR we're currently building up for an aggregate
      initializer.  */
   tree ctor;
@@ -1831,7 +1831,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
          /* Track the callee's evaluated SAVE_EXPRs so that we can forget
             their values after the call.  */
          constexpr_ctx ctx_with_save_exprs = *ctx;
-         hash_set<tree> save_exprs;
+         auto_vec<tree, 10> save_exprs;
          ctx_with_save_exprs.save_exprs = &save_exprs;
          ctx_with_save_exprs.call = &new_call;
 
@@ -1862,9 +1862,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
            }
 
          /* Forget the saved values of the callee's SAVE_EXPRs.  */
-         for (hash_set<tree>::iterator iter = save_exprs.begin();
-              iter != save_exprs.end(); ++iter)
-           ctx_with_save_exprs.values->remove (*iter);
+         unsigned int i;
+         tree save_expr;
+         FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
+           ctx_with_save_exprs.values->remove (save_expr);
 
          /* Remove the parms/result from the values map.  Is it worth
             bothering to do this when the map itself is only live for
@@ -4190,7 +4191,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
     default:
       gcc_unreachable ();
     }
-  hash_set<tree> save_exprs;
+  auto_vec<tree, 10> save_exprs;
   new_ctx.save_exprs = &save_exprs;
   do
     {
@@ -4234,9 +4235,11 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
        }
 
       /* Forget saved values of SAVE_EXPRs.  */
-      for (hash_set<tree>::iterator iter = save_exprs.begin();
-          iter != save_exprs.end(); ++iter)
-       new_ctx.values->remove (*iter);
+      unsigned int i;
+      tree save_expr;
+      FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
+       new_ctx.values->remove (save_expr);
+      save_exprs.truncate (0);
 
       if (++count >= constexpr_loop_limit)
        {
@@ -4256,9 +4259,10 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
         && !*non_constant_p);
 
   /* Forget saved values of SAVE_EXPRs.  */
-  for (hash_set<tree>::iterator iter = save_exprs.begin();
-       iter != save_exprs.end(); ++iter)
-    new_ctx.values->remove (*iter);
+  unsigned int i;
+  tree save_expr;
+  FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
+    new_ctx.values->remove (save_expr);
 
   return NULL_TREE;
 }
@@ -4616,7 +4620,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                            non_constant_p, overflow_p);
          ctx->values->put (t, r);
          if (ctx->save_exprs)
-           ctx->save_exprs->add (t);
+           ctx->save_exprs->safe_push (t);
        }
       break;
 
index b7550a2..73ac51a 100644 (file)
@@ -1,3 +1,8 @@
+2019-03-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/89652
+       * g++.dg/cpp1y/constexpr-89652.C: New test.
+
 2019-03-13  Harald Anlauf  <anlauf@gmx.de>
 
        PR fortran/87045
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89652.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89652.C
new file mode 100644 (file)
index 0000000..8d0631e
--- /dev/null
@@ -0,0 +1,36 @@
+// PR c++/89652
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+template <typename T> constexpr auto foo (T &e) { return e.foo (); }
+template <typename T> constexpr auto bar (T &e) { return foo (e); }
+template <typename T, int N> struct A { typedef T a[N]; };
+template <typename T, unsigned long N> struct B {
+  typedef T *b;
+  typename A<T, N>::a d;
+  constexpr b foo () { return d; }
+};
+template <typename> struct C { long m; };
+struct D { long n; };
+template <typename, unsigned long> struct E {
+  B<C<int>, 1>::b p;
+  constexpr D operator* () { return {p->m}; }
+  constexpr E operator++ (int) { auto a{*this}; ++p; return a; }
+};
+template <typename T, unsigned long N>
+constexpr bool operator!= (E<T, N> a, E<T, N>) { return a.p; }
+template <unsigned long N, typename T, unsigned long M>
+constexpr auto baz (B<T, M> s, B<D, N>)
+{
+  B<D, M> t{};
+  auto q{foo (t)};
+  using u = E<T, M>;
+  auto v = u{bar (s)};
+  auto w = u{};
+  while (v != w)
+    *q++ = *v++;
+  return t;
+}
+constexpr auto a = B<C<int>, 5>{};
+auto b = B<D, 0>{};
+auto c = baz (a, b);