2019-03-12 Jakub Jelinek PR c++/89652 * constexpr.c (cxx_eval_loop_expr): Only remove SAVE_EXPRs that are still in new_ctx.values hash_map. * g++.dg/cpp1y/constexpr-89652.C: New test. --- gcc/cp/constexpr.c.jj 2019-03-08 08:43:23.529496048 +0100 +++ gcc/cp/constexpr.c 2019-03-11 15:11:32.081334270 +0100 @@ -4236,7 +4236,8 @@ cxx_eval_loop_expr (const constexpr_ctx /* Forget saved values of SAVE_EXPRs. */ for (hash_set::iterator iter = save_exprs.begin(); iter != save_exprs.end(); ++iter) - new_ctx.values->remove (*iter); + if (new_ctx.values->get (*iter)) + new_ctx.values->remove (*iter); if (++count >= constexpr_loop_limit) { @@ -4258,7 +4259,8 @@ cxx_eval_loop_expr (const constexpr_ctx /* Forget saved values of SAVE_EXPRs. */ for (hash_set::iterator iter = save_exprs.begin(); iter != save_exprs.end(); ++iter) - new_ctx.values->remove (*iter); + if (new_ctx.values->get (*iter)) + new_ctx.values->remove (*iter); return NULL_TREE; } --- gcc/testsuite/g++.dg/cpp1y/constexpr-89652.C.jj 2019-03-11 15:14:21.877561575 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-89652.C 2019-03-11 15:16:11.962763933 +0100 @@ -0,0 +1,36 @@ +// PR c++/89652 +// { dg-do compile { target c++14 } } +// { dg-options "" } + +template constexpr auto foo (T &e) { return e.foo (); } +template constexpr auto bar (T &e) { return foo (e); } +template struct A { typedef T a[N]; }; +template struct B { + typedef T *b; + typename A::a d; + constexpr b foo () { return d; } +}; +template struct C { long m; }; +struct D { long n; }; +template struct E { + B, 1>::b p; + constexpr D operator* () { return {p->m}; } + constexpr E operator++ (int) { auto a{*this}; ++p; return a; } +}; +template +constexpr bool operator!= (E a, E) { return a.p; } +template +constexpr auto baz (B s, B) +{ + B t{}; + auto q{foo (t)}; + using u = E; + auto v = u{bar (s)}; + auto w = u{}; + while (v != w) + *q++ = *v++; + return t; +} +constexpr auto a = B, 5>{}; +auto b = B{}; +auto c = baz (a, b);