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

Reply via email to