From: Jason Merrill Date: Fri, 14 Mar 2014 19:06:54 +0000 (-0400) Subject: re PR c++/58678 (pykde4-4.11.2 link error (devirtualization too trigger happy)) X-Git-Tag: releases/gcc-4.9.0~448 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7e343703fe22b55b9e6a446a0c0fdef989207c9d;p=thirdparty%2Fgcc.git re PR c++/58678 (pykde4-4.11.2 link error (devirtualization too trigger happy)) PR c++/58678 * search.c (dfs_get_pure_virtuals): Treat the destructor of an abstract class as pure. From-SVN: r208573 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d90b9881c313..b752ebe914f0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2014-03-14 Jason Merrill + + PR c++/58678 + * search.c (dfs_get_pure_virtuals): Treat the destructor of an + abstract class as pure. + 2014-03-13 Paolo Carlini PR c++/60383 diff --git a/gcc/cp/search.c b/gcc/cp/search.c index c3eed90f6c36..66c6df5215e7 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 000000000000..c4ac6940a983 --- /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" } }