Patchwork C++ PATCH for c++/54341, c++/54253 (constexpr and virtual functions)

login
register
mail settings
Submitter Jason Merrill
Date Sept. 6, 2012, 3:37 p.m.
Message ID <5048C356.6000701@redhat.com>
Download mbox | patch
Permalink /patch/182234/
State New
Headers show

Comments

Jason Merrill - Sept. 6, 2012, 3:37 p.m.
Vtables were causing several different problems for constexpr:

1) Value-initializing a nearly-empty class (that has a vptr but no data) 
meant two initializers for a single base.  Fixed by not bothering to 
zero out a type with no data before calling its constructor.

2) A primary base is allocated at offset 0 even if it isn't at the 
beginning of the base-clause, but constructors initialize bases in the 
order of the base-clause.  So we need to do some adjustment to get our 
CONSTRUCTOR in the right order.

Looking at issue 2 also led me to notice that we were failing to ignore 
base fields as intended in cx_check_missing_mem_inits.

Tested x86_64-pc-linux-gnu, applying to trunk.
Matthias Klose - Sept. 7, 2012, 4:33 p.m.
On 06.09.2012 17:37, Jason Merrill wrote:
> Vtables were causing several different problems for constexpr:
> 
> 1) Value-initializing a nearly-empty class (that has a vptr but no data) meant
> two initializers for a single base.  Fixed by not bothering to zero out a type
> with no data before calling its constructor.
> 
> 2) A primary base is allocated at offset 0 even if it isn't at the beginning of
> the base-clause, but constructors initialize bases in the order of the
> base-clause.  So we need to do some adjustment to get our CONSTRUCTOR in the
> right order.
> 
> Looking at issue 2 also led me to notice that we were failing to ignore base
> fields as intended in cx_check_missing_mem_inits.

thanks for the fix. looked at backporting this for 4.7. Is it really necessary
to use C++ only syntax for this kind of patches, which are a candidate for 4.7?

thanks, Matthias

Patch

commit 439320363040fdcdadc1a500cf4319f5f8325bad
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Sep 5 22:26:43 2012 -0400

    	PR c++/54341
    	PR c++/54253
    	* semantics.c (sort_constexpr_mem_initializers): New.
    	(build_constexpr_constructor_member_initializers): Use it.
    	(cx_check_missing_mem_inits): Skip artificial fields.
    	* init.c (expand_aggr_init_1): Don't zero out a class
    	with no data.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 09288f8..561477a 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1742,8 +1742,10 @@  expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
      that's value-initialization.  */
   if (init == void_type_node)
     {
-      /* If no user-provided ctor, we need to zero out the object.  */
-      if (!type_has_user_provided_constructor (type))
+      /* If the type has data but no user-provided ctor, we need to zero
+	 out the object.  */
+      if (!type_has_user_provided_constructor (type)
+	  && !is_really_empty_class (type))
 	{
 	  tree field_size = NULL_TREE;
 	  if (exp != true_exp && CLASSTYPE_AS_BASE (type) != type)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f64246d..7cd1468 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5895,6 +5895,35 @@  check_constexpr_ctor_body (tree last, tree list)
   return ok;
 }
 
+/* VEC is a vector of constructor elements built up for the base and member
+   initializers of a constructor for TYPE.  They need to be in increasing
+   offset order, which they might not be yet if TYPE has a primary base
+   which is not first in the base-clause.  */
+
+static VEC(constructor_elt,gc) *
+sort_constexpr_mem_initializers (tree type, VEC(constructor_elt,gc) *vec)
+{
+  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (type)
+      || (CLASSTYPE_PRIMARY_BINFO (type)
+	  == BINFO_BASE_BINFO (TYPE_BINFO (type), 0)))
+    return vec;
+
+  /* Find the element for the primary base and move it to the beginning of
+     the vec.  */
+  tree pri = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (type));
+  VEC(constructor_elt,gc) &v = *vec;
+  int pri_idx;
+
+  for (pri_idx = 1; ; ++pri_idx)
+    if (TREE_TYPE (v[pri_idx].index) == pri)
+      break;
+  constructor_elt pri_elt = v[pri_idx];
+  for (int i = 0; i < pri_idx; ++i)
+    v[i+1] = v[i];
+  v[0] = pri_elt;
+  return vec;
+}
+
 /* Build compile-time evalable representations of member-initializer list
    for a constexpr constructor.  */
 
@@ -5957,6 +5986,7 @@  build_constexpr_constructor_member_initializers (tree type, tree body)
 	      return body;
 	    }
 	}
+      vec = sort_constexpr_mem_initializers (type, vec);
       return build_constructor (type, vec);
     }
   else
@@ -6075,14 +6105,16 @@  cx_check_missing_mem_inits (tree fun, tree body, bool complain)
 	{
 	  index = CONSTRUCTOR_ELT (body, i)->index;
 	  /* Skip base and vtable inits.  */
-	  if (TREE_CODE (index) != FIELD_DECL)
+	  if (TREE_CODE (index) != FIELD_DECL
+	      || DECL_ARTIFICIAL (index))
 	    continue;
 	}
       for (; field != index; field = DECL_CHAIN (field))
 	{
 	  tree ftype;
 	  if (TREE_CODE (field) != FIELD_DECL
-	      || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field)))
+	      || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
+	      || DECL_ARTIFICIAL (field))
 	    continue;
 	  ftype = strip_array_types (TREE_TYPE (field));
 	  if (type_has_constexpr_default_constructor (ftype))
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual2.C
new file mode 100644
index 0000000..86040a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual2.C
@@ -0,0 +1,24 @@ 
+// PR c++/54341
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+struct enable_shared_from_this
+{
+  constexpr enable_shared_from_this(); // { dg-warning "used but never defined" }
+
+private:
+  int mem;
+};
+
+class VTableClass {
+public:
+    virtual void someVirtualMethod() { }
+};
+
+class SomeClass : public enable_shared_from_this< SomeClass >, public
+VTableClass { };
+
+SomeClass* createInstance()
+{
+    return new SomeClass;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual3.C
new file mode 100644
index 0000000..de446bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual3.C
@@ -0,0 +1,42 @@ 
+// PR c++/54253
+// { dg-do compile { target c++11 } }
+
+namespace A {
+  class Base {
+    int x;
+  public:
+    constexpr Base(int x) : x(x) {}
+  };
+
+  class Base2 {
+  public:
+    virtual void fun() {}
+  };
+
+  class Derived : public Base2, public Base {
+  public:
+    constexpr Derived() : Base2(), Base(5) {}
+  };
+
+  constexpr Derived der;
+}
+
+namespace B {
+  class Base {
+    int x;
+  public:
+    constexpr Base() : x(5) {}
+  };
+
+  class Base2 {
+  public:
+    virtual void fun() {}
+  };
+
+  class Derived : public Base, public Base2 {
+  public:
+    constexpr Derived() {}
+  };
+
+  constexpr Derived der;
+}