Here, when we look at the value of an empty base, we would first make
sure that the complete object is constant.  But we were in the middle
of initializing one of the fields of the complete object, so the
corresponding CONSTRUCTOR value was NULL, leading to a crash when
trying to determine if it's constant.

There are two issues here:

1) We shouldn't crash.  We should treat a field under initialization
as non-constant.
2) We shouldn't require that the complete object be constant.  It's
fine to use the value of a fully constructed subobject while
initializing another member.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 5d650f368849196d53af19decdfcc5217ca0301b
Author: Jason Merrill <ja...@redhat.com>
Date:   Sun Apr 9 00:49:10 2017 -0400

            PR c++/80294 - ICE with constexpr and inheritance.
    
            * constexpr.c (reduced_constant_expression_p):
            A null constructor element is non-constant.
            (cxx_eval_indirect_ref): Don't VERIFY_CONSTANT before
            returning an empty base.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 3ca3560..9dde4a4 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1716,8 +1716,13 @@ reduced_constant_expression_p (tree t)
       /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR.  */
       tree elt; unsigned HOST_WIDE_INT idx;
       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), idx, elt)
-       if (!reduced_constant_expression_p (elt))
-         return false;
+       {
+         if (!elt)
+           /* We're in the middle of initializing this element.  */
+           return false;
+         if (!reduced_constant_expression_p (elt))
+           return false;
+       }
       return true;
 
     default:
@@ -3153,12 +3158,10 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
   if (*non_constant_p)
     return t;
 
-  /* If we're pulling out the value of an empty base, make sure
-     that the whole object is constant and then return an empty
+  /* If we're pulling out the value of an empty base, just return an empty
      CONSTRUCTOR.  */
   if (empty_base && !lval)
     {
-      VERIFY_CONSTANT (r);
       r = build_constructor (TREE_TYPE (t), NULL);
       TREE_CONSTANT (r) = true;
     }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-empty3.C 
b/gcc/testsuite/g++.dg/cpp1y/constexpr-empty3.C
new file mode 100644
index 0000000..37e4a53
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-empty3.C
@@ -0,0 +1,14 @@
+// PR c++/80294
+// { dg-do compile { target c++14 } }
+// { dg-final { scan-assembler-not "static_init" } }
+
+struct A {
+  constexpr int f() { A a = *this; return 42; }
+};
+struct B: A
+{
+  int i;
+  constexpr B(): i(f()) {}
+};
+
+B b;

Reply via email to