On 2/1/21 7:48 AM, Patrick Palka wrote:
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?

OK.

-- >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() {}


Reply via email to