On 10/05/16 19:49, Jason Merrill wrote:

But DR 1658 says that B::B is *not* deleted (because A is not a
potentially constructed subobject).  Implementing that might be
simpler than trying to have a deleted complete and non-deleted base
constructor variant.

Always better to read the actual DR rather than infer it from the bug report. Here's an updated patch, which also addresses DR1611 (the dtor case).

emit_mem_initializers and push_base_cleanups only operate on vbases when !ABSTRACT_CLASS_TYPE_P (we'll have already checked that's valid or not, so we don't care about what version of C++ this is).

synthesized_method_walk only scans vbases (for cdtors) when !BSTRACT_CLASS_TYPE_P or < c++14. This is the validity check.

much simples. ok?

nathan

2016-10-06  Nathan Sidwell  <nat...@acm.org>

	PR c++/64433
	DR1658, DR1611
	* init.c (emit_mem_initializers): Don't construct vbases of
	abstract classes.
	(push_base_cleanups): Don't push vbase cleanups for abstract class
	when in C++14 mode.
	* method.c (synthethesized_method_walk): Don't walk vbases of
	abstract classes when in C++14 mode.

	PR c++/66443
	* g++.dg/cpp0x/pr66443-cxx11.C: New.
	* g++.dg/cpp0x/pr66443-cxx11-2.C: New.
	* g++.dg/cpp1y/pr66443-cxx14.C: New
	* g++.dg/cpp1y/pr66443-cxx14-2.C: New.
	* g++.dg/cpp1y/pr66443-cxx14-3.C: New.

Index: cp/init.c
===================================================================
--- cp/init.c	(revision 240838)
+++ cp/init.c	(working copy)
@@ -1150,9 +1150,7 @@ emit_mem_initializers (tree mem_inits)
 	}
 
       /* Initialize the base.  */
-      if (BINFO_VIRTUAL_P (subobject))
-	construct_virtual_base (subobject, arguments);
-      else
+      if (!BINFO_VIRTUAL_P (subobject))
 	{
 	  tree base_addr;
 
@@ -1166,6 +1164,10 @@ emit_mem_initializers (tree mem_inits)
                               tf_warning_or_error);
 	  expand_cleanup_for_base (subobject, NULL_TREE);
 	}
+      else if (!ABSTRACT_CLASS_TYPE_P (current_class_type))
+	/* C++14 DR1658 Means we do not have to construct vbases of
+	   abstract classes.  */
+	construct_virtual_base (subobject, arguments);
     }
   in_base_initializer = 0;
 
@@ -4527,7 +4529,8 @@ push_base_cleanups (void)
   vec<tree, va_gc> *vbases;
 
   /* Run destructors for all virtual baseclasses.  */
-  if (CLASSTYPE_VBASECLASSES (current_class_type))
+  if (!ABSTRACT_CLASS_TYPE_P (current_class_type)
+      && CLASSTYPE_VBASECLASSES (current_class_type))
     {
       tree cond = (condition_conversion
 		   (build2 (BIT_AND_EXPR, integer_type_node,
Index: cp/method.c
===================================================================
--- cp/method.c	(revision 240838)
+++ cp/method.c	(working copy)
@@ -1319,12 +1319,12 @@ walk_field_subobs (tree fields, tree fnn
     }
 }
 
-/* The caller wants to generate an implicit declaration of SFK for CTYPE
-   which is const if relevant and CONST_P is set.  If spec_p, trivial_p and
-   deleted_p are non-null, set their referent appropriately.  If diag is
-   true, we're either being called from maybe_explain_implicit_delete to
-   give errors, or if constexpr_p is non-null, from
-   explain_invalid_constexpr_fn.  */
+/* The caller wants to generate an implicit declaration of SFK for
+   CTYPE which is const if relevant and CONST_P is set.  If SPEC_P,
+   TRIVIAL_P, DELETED_P or CONSTEXPR_P are non-null, set their
+   referent appropriately.  If DIAG is true, we're either being called
+   from maybe_explain_implicit_delete to give errors, or if
+   CONSTEXPR_P is non-null, from explain_invalid_constexpr_fn.  */
 
 static void
 synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
@@ -1534,9 +1534,13 @@ synthesized_method_walk (tree ctype, spe
     }
 
   vbases = CLASSTYPE_VBASECLASSES (ctype);
-  if (vec_safe_is_empty (vbases))
+  if (assign_p)
+    /* No need to examine vbases here.  */;
+  else if (vec_safe_is_empty (vbases))
     /* No virtual bases to worry about.  */;
-  else if (!assign_p)
+  else if (ABSTRACT_CLASS_TYPE_P (ctype) && cxx_dialect >= cxx14)
+    /* Vbase cdtors are not relevant.  */;
+  else
     {
       if (constexpr_p)
 	*constexpr_p = false;
Index: testsuite/g++.dg/cpp0x/pr66443-cxx11-2.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr66443-cxx11-2.C	(nonexistent)
+++ testsuite/g++.dg/cpp0x/pr66443-cxx11-2.C	(working copy)
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++11_only } }
+
+class C;
+
+  
+struct A {
+  A ();
+private:
+  ~A (){ }
+  friend class C;
+};
+
+struct B : virtual A {  // { dg-error "is private" }
+  B ();
+  virtual bool Ok () = 0; // abstract
+};
+
+struct C : B {  // { dg-error "use of deleted" }
+  C ();
+  virtual bool Ok ();
+};
+
+C c; // { dg-error "use of deleted" }
Index: testsuite/g++.dg/cpp0x/pr66443-cxx11.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr66443-cxx11.C	(nonexistent)
+++ testsuite/g++.dg/cpp0x/pr66443-cxx11.C	(working copy)
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11_only } }
+
+// pr c++/66443 it is still ill-formed in C++ 11 for a synthesized
+// ctor that's deleted only because of virtual base construction
+
+static bool a_made;
+
+struct A { // { dg-message "candidate" }
+  A( int ) { a_made = true; } // { dg-message "candidate" }
+};
+
+struct B: virtual A { // { dg-message "no matching function" }
+  int m;
+  virtual void Frob () = 0;
+};
+
+class C: public B {
+public:
+  C();
+  virtual void Frob ();
+};
+
+void C::Frob ()
+{
+}
+
+C::C ()
+  : A( 1 ) // { dg-error "deleted function" }
+{ }
+
Index: testsuite/g++.dg/cpp1y/pr66443-cxx14-2.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr66443-cxx14-2.C	(nonexistent)
+++ testsuite/g++.dg/cpp1y/pr66443-cxx14-2.C	(working copy)
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++14 } }
+
+// pr c++/66443 a synthesized ctor of an abstract class that's deleted
+// only because of virtual base construction doesn't stop a derived
+// class using it as a base object constructor (provided it has a
+// suitable ctor invocation of the virtual base).
+
+// However we should still complain if the intermediate base is a
+// non-abstract type.
+
+static int a_made;
+
+struct A {
+  A *m_a = this;
+  A (int) { a_made++; }
+};
+
+struct B : virtual A { // { dg-error "no matching function" }
+  A *m_b = this;
+  virtual bool Ok (); // not abstract
+};
+
+bool B::Ok ()
+{
+  return false;
+}
+
+
+B b; // { dg-error "deleted" }
Index: testsuite/g++.dg/cpp1y/pr66443-cxx14-3.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr66443-cxx14-3.C	(nonexistent)
+++ testsuite/g++.dg/cpp1y/pr66443-cxx14-3.C	(working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+// DR 1658, inaccessible dtor of virtual base doesn't affect an
+// abstract class
+
+int a_unmade;
+
+class C;
+
+  
+struct A {
+private:
+  ~A (){ a_unmade++; }
+  friend class C;
+};
+
+struct B : virtual A {
+  virtual bool Ok () = 0; // abstract
+};
+
+struct C : B {
+  virtual bool Ok ();
+};
+
+C c;
Index: testsuite/g++.dg/cpp1y/pr66443-cxx14.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr66443-cxx14.C	(nonexistent)
+++ testsuite/g++.dg/cpp1y/pr66443-cxx14.C	(working copy)
@@ -0,0 +1,47 @@
+// { dg-do run { target c++14 } }
+
+// pr c++/66443 a synthesized ctor of an abstract class that's deleted
+// only because of virtual base construction doesn't stop a derived
+// class using it as a base object constructor (provided it has a
+// suitable ctor invocation of the virtual base).
+
+static int a_made;
+
+struct A {
+  A *m_a = this;
+  A (int) { a_made++; }
+};
+
+struct B : virtual A {
+  A *m_b = this;
+  virtual bool Ok () = 0; // abstract
+};
+
+struct C : B {
+  // C::m_c is placed where a complete B object would put A
+  int m_c = 1729;
+public:
+  C();
+  virtual bool Ok ();
+};
+
+bool C::Ok ()
+{
+  // check everyone agreed on where A is
+  return a_made == 1 && m_a == this && m_b == this && m_c == 1729;
+}
+
+C::C ()
+  : A (1) // Explicit call of A's ctor
+{  }
+
+bool Ok (C &c)
+{
+}
+
+int main ()
+{
+  C c;
+
+  return !c.Ok ();
+}

Reply via email to