diff mbox

C++ PATCH for c++/58678 (devirt vs. KDE)

Message ID 5323528C.1080308@redhat.com
State New
Headers show

Commit Message

Jason Merrill March 14, 2014, 7:03 p.m. UTC
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.
diff mbox

Patch

commit 32cc4489140da9dd154f8ba5ad3fc904efb23d55
Author: Jason Merrill <jason@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" } }