+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.
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;
/* 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;
}
/* 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
default:
gcc_unreachable ();
}
- hash_set<tree> save_exprs;
+ auto_vec<tree, 10> save_exprs;
new_ctx.save_exprs = &save_exprs;
do
{
}
/* 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)
{
&& !*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;
}
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;
--- /dev/null
+// 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);