On Fri, 29 Jan 2021, Jason Merrill wrote: > On 1/29/21 12:28 PM, Patrick Palka wrote: > > In this testcase we're crash during constexpr evaluation of the > > ARRAY_REF b[0] as part of folding the lambda's by-copy capture of b > > (which is encoded as a VEC_INIT_EXPR<b>). Since A's default constructor > > is not yet defined, b's initializer is not actually constant, but > > because A is an empty type, evaluation of the referent b from > > cxx_eval_array_ref yields an empty CONSTRUCTOR. From there we proceed > > to {}-initialize the missing array element at index 0. We crash from > > verify_ctor_sanity during evaluation of this initializer because we > > updated constexpr_ctx::ctor without updating ::object; the former has > > type A[3] and the latter is the target of the TARGET_EXPR for b[0][0] > > created from cxx_eval_vec_init_1 (and so has type A). > > > > This patch conservatively fixes this issue by clearing new_ctx.object at > > the same time that we set new_ctx.ctor. Strictly speaking, the object > > under construction should perhaps be the ARRAY_REF itself > > Yes. > > > but I haven't > > been able to come up with a testcase for which this difference matters. > > I suspect that any case where it would matter wouldn't get to this point, > because we would have already built up the initializer under digest_init. > > But I also think it shouldn't hurt to use 't' as new_ctx.object, so let's do > that.
Sounds good. I had convinced myself earlier that using 't' wouldn't be quite right and that we ought to use something like cxx_eval_array_reference(t, /*lval=*/true) as new_ctx.object instead in order to ensure the operands of the ARRAY_REF are fully reduced. But it seems this isn't necessary since the routines which inspect ctx->object already pass it through cxx_eval_constant_expression appropriately. So using 't', even when it's unreduced, should be safe in this respect. Does the following look OK for trunk/10? -- >8 -- Subject: [PATCH] c++: Fix ICE from verify_ctor_sanity [PR98295] In this testcase we're crashing during constexpr evaluation of the ARRAY_REF b[0] as part of evaluation of the lambda's by-copy capture of b (which is encoded as a VEC_INIT_EXPR<b>). Since A's constexpr default constructor is not yet defined, b's initialization is not actually constant, but because A is an empty type, evaluation of the referent b from cxx_eval_array_ref is successful and yields an empty CONSTRUCTOR. Since the CONSTRUCTOR is empty, we {}-initialize the desired array element, and we end up crashing from verify_ctor_sanity during evaluation of this initializer because we updated new_ctx.ctor without updating new_ctx.object: the former now has type A[3] and the latter is still the target of a TARGET_EXPR for b[0][0] created from cxx_eval_vec_init_1 (and so has type A). This patch fixes this by setting new_ctx.object appropriately at the same time that we set new_ctx.ctor from cxx_eval_array_reference. gcc/cp/ChangeLog: PR c++/98295 * constexpr.c (cxx_eval_array_reference): Also set new_ctx.object when setting new_ctx.ctor. gcc/testsuite/ChangeLog: PR c++/98295 * g++.dg/cpp0x/constexpr-98295.C: New test. --- gcc/cp/constexpr.c | 1 + gcc/testsuite/g++.dg/cpp0x/constexpr-98295.C | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-98295.C diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index baa97a0ef17..1dbc2db9643 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3760,6 +3760,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, tree empty_ctor = build_constructor (init_list_type_node, NULL); val = digest_init (elem_type, empty_ctor, tf_warning_or_error); new_ctx = *ctx; + new_ctx.object = t; new_ctx.ctor = build_constructor (elem_type, NULL); ctx = &new_ctx; } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-98295.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-98295.C new file mode 100644 index 00000000000..930bd5a67da --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-98295.C @@ -0,0 +1,11 @@ +// PR c++/98295 +// { dg-do compile { target c++11 } } + +struct A { constexpr A(); }; + +void f() { + A b[2][3]; + [b] { }; +} + +constexpr A::A() {} -- 2.30.0.335.ge6362826a0