re PR c++/89652 (ICE during constexpr evaluation)

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
This commit is contained in:
Jakub Jelinek 2019-03-14 09:13:09 +01:00 committed by Jakub Jelinek
parent 7da0bca130
commit 0ee285909b
4 changed files with 70 additions and 13 deletions

View 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.

View 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;

View 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

View File

@ -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);