Honza suggested that if the destructor for an abstract class can't ever be called through the vtable, the front end could avoid referring to it from the vtable. This patch replaces such a destructor with __cxa_pure_virtual in the vtable.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 32cc4489140da9dd154f8ba5ad3fc904efb23d55
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Mar 14 14:10:03 2014 -0400

    	PR c++/58678
    	* search.c (dfs_get_pure_virtuals): Treat the destructor of an
    	abstract class as pure.

diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index c3eed90..66c6df5 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -2096,6 +2096,22 @@ dfs_get_pure_virtuals (tree binfo, void *data)
 	if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))
 	  vec_safe_push (CLASSTYPE_PURE_VIRTUALS (type), BV_FN (virtuals));
     }
+  /* Treat a virtual destructor in an abstract class as pure even if it
+     isn't declared as pure; there is no way it would be called through the
+     vtable except during construction, which causes undefined behavior.  */
+  if (binfo == TYPE_BINFO (type)
+      && CLASSTYPE_PURE_VIRTUALS (type)
+      && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+    {
+      tree dtor = CLASSTYPE_DESTRUCTORS (type);
+      if (DECL_VIRTUAL_P (dtor) && !DECL_PURE_VIRTUAL_P (dtor))
+	{
+	  tree clone;
+	  DECL_PURE_VIRTUAL_P (dtor) = true;
+	  FOR_EACH_CLONE (clone, dtor)
+	    DECL_PURE_VIRTUAL_P (clone) = true;
+	}
+    }
 
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-30.C b/gcc/testsuite/g++.dg/ipa/devirt-30.C
new file mode 100644
index 0000000..c4ac694
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-30.C
@@ -0,0 +1,25 @@
+// PR c++/58678
+// { dg-options "-O3 -fdump-ipa-devirt" }
+
+// We shouldn't speculatively devirtualize to ~B because B is an abstract
+// class; any actual object passed to f will be of some derived class which
+// has its own destructor.
+
+struct A
+{
+  virtual void f() = 0;
+  virtual ~A();
+};
+
+struct B : A
+{
+  virtual ~B() {}
+};
+
+void f(B* b)
+{
+  delete b;
+}
+
+// { dg-final { scan-ipa-dump-not "Speculatively devirtualizing" "devirt" } }
+// { dg-final { cleanup-ipa-dump "devirt" } }

Reply via email to