In this testcase we were getting confused when trying to initialize an
empty base with a CONSTRUCTOR: the initialization target was
*(base*)this, which constexpr evaluation resolves to the object
argument, which isn't actually of the base type. So we end up storing a
base constructor as the value of the derived object, and confusion ensues.
In this situation there's no store that can be done, since there is no
field for the empty base, so we shouldn't try to do a store.
Tested x86_64-pc-linux-gnu, applying to trunk and 5.2.
commit 28222533c0569d48d8d3d8ad3176750fe6080866
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Apr 28 12:59:35 2015 -0400
PR c++/65896
* constexpr.c (cxx_eval_store_expression): Don't try to actually
store an empty class.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 403c7cf..9ebb640 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2580,12 +2580,25 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
/* First we figure out where we're storing to. */
tree target = TREE_OPERAND (t, 0);
+ tree type = TREE_TYPE (target);
target = cxx_eval_constant_expression (ctx, target,
true,
non_constant_p, overflow_p);
if (*non_constant_p)
return t;
+ if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (target), type))
+ {
+ /* For initialization of an empty base, the original target will be
+ *(base*)this, which the above evaluation resolves to the object
+ argument, which has the derived type rather than the base type. In
+ this situation, just evaluate the initializer and return, since
+ there's no actual data to store. */
+ gcc_assert (is_empty_class (type));
+ return cxx_eval_constant_expression (ctx, init, false,
+ non_constant_p, overflow_p);
+ }
+
/* And then find the underlying variable. */
vec<tree,va_gc> *refs = make_tree_vector();
tree object = NULL_TREE;
@@ -2622,7 +2635,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- tree type = TREE_TYPE (object);
+ type = TREE_TYPE (object);
while (!refs->is_empty())
{
if (*valp == NULL_TREE)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty9.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty9.C
new file mode 100644
index 0000000..26b4863
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty9.C
@@ -0,0 +1,18 @@
+// PR c++/65896
+// { dg-do compile { target c++11 } }
+
+struct base {};
+
+struct derived : base {
+ constexpr derived():
+ base{},
+ m_value(0) {
+ }
+ int m_value;
+};
+
+constexpr int by_ref(derived && value) {
+ return value.m_value;
+}
+
+constexpr int value = by_ref(derived{});