> On 02/28/2014 03:56 PM, Jan Hubicka wrote: > >I think we can safely test here DECL_ARTIFICIAL && (DECL_EXTERNAL || > >DECL_COMDAT). If the dtor is going to be output anyway, we are safe to use > >it. > > We already skipped DECL_EXTERNAL decls, and artificial members are > always DECL_COMDAT, but I'll add the COMDAT check. > > >Are those programs valid by C++ standard? (I believe it is not valid to > >include > >stuff whose implementation you do not link with.). > > Symbol visibility is outside the scope of the standard. > > >If we just want to avoid > >breaking python and libreoffice (I fixed libreoffice part however), we may > >just > >go with the ipa-devirt change as you propose (with external&comdat check). > > > >If this is an correctness issue, I think we want to be safe that other > >optimizations > >won't do the same. In that case your check seems misplaced. > > > >If DECL_ARTIFICIAL destructors are not safe to inline, I would add it into > >function_attribute_inlinable_p. If the dtor is not safe to refer, then I > >would > >add it into can_refer_decl_in_current_unit_p > > >Both such changes would however inhibit quite some optimization, since > >artificial destructors are quite common case, right? Or is there some reason > >why > >only speculative devirtualization count possibly work out reference to these? > > Normally, it's fine to inline destructors, and refer to them. The > problem comes when we turn what had been a virtual call (which goes > through the vtable that is hidden in the DSO) into a direct call to > a hidden function. We don't do that for user-defined virtual > functions because the user controls whether or not they are defined > in the header, and we don't devirtualize if no definition is > available, but implicitly-declared functions are different because > the user has no way to prevent the definition from being available. > > This also isn't a problem for cprop devirtualization, because in > that situation we must have already referred to the vtable.
Is this always the case? For normal virtual method you can have something like: foo(class bla a) { a->bar(); } Here we will devirutalize bar into bla's method without ever seeing the vtable. I am not sure if I can construct a testcase for dtor w/o referencing the vtable, since generally those are cases where dtor is generated autmatically. But it is a bit fragile assumption to be made. Jan > > Jason > > commit 2a05a09c268ce3abb373aa86cf731d20aac8dd7a > Author: Jason Merrill <ja...@redhat.com> > Date: Fri Feb 28 14:03:19 2014 -0500 > > PR c++/58678 > * ipa-devirt.c (ipa_devirt): Don't choose an implicitly-declared > function. > > diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c > index 21649cb..2f84f17 100644 > --- a/gcc/ipa-devirt.c > +++ b/gcc/ipa-devirt.c > @@ -1710,7 +1710,7 @@ ipa_devirt (void) > > int npolymorphic = 0, nspeculated = 0, nconverted = 0, ncold = 0; > int nmultiple = 0, noverwritable = 0, ndevirtualized = 0, nnotdefined = 0; > - int nwrong = 0, nok = 0, nexternal = 0;; > + int nwrong = 0, nok = 0, nexternal = 0, nartificial = 0; > > FOR_EACH_DEFINED_FUNCTION (n) > { > @@ -1820,6 +1820,17 @@ ipa_devirt (void) > nexternal++; > continue; > } > + /* Don't use an implicitly-declared destructor (c++/58678). */ > + struct cgraph_node *non_thunk_target > + = cgraph_function_node (likely_target); > + if (DECL_ARTIFICIAL (non_thunk_target->decl) > + && DECL_COMDAT (non_thunk_target->decl)) > + { > + if (dump_file) > + fprintf (dump_file, "Target is artificial\n\n"); > + nartificial++; > + continue; > + } > if (cgraph_function_body_availability (likely_target) > <= AVAIL_OVERWRITABLE > && symtab_can_be_discarded (likely_target)) > @@ -1862,10 +1873,10 @@ ipa_devirt (void) > " %i speculatively devirtualized, %i cold\n" > "%i have multiple targets, %i overwritable," > " %i already speculated (%i agree, %i disagree)," > - " %i external, %i not defined\n", > + " %i external, %i not defined, %i artificial\n", > npolymorphic, ndevirtualized, nconverted, ncold, > nmultiple, noverwritable, nspeculated, nok, nwrong, > - nexternal, nnotdefined); > + nexternal, nnotdefined, nartificial); > return ndevirtualized ? TODO_remove_functions : 0; > } > > diff --git a/gcc/testsuite/g++.dg/ipa/devirt-28.C > b/gcc/testsuite/g++.dg/ipa/devirt-28.C > new file mode 100644 > index 0000000..e18b818 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ipa/devirt-28.C > @@ -0,0 +1,17 @@ > +// PR c++/58678 > +// { dg-options "-O3 -fdump-ipa-devirt" } > + > +struct A { > + virtual ~A(); > +}; > +struct B : A { > + virtual int m_fn1(); > +}; > +void fn1(B* b) { > + delete b; > +} > + > +// { dg-final { scan-assembler-not "_ZN1AD2Ev" } } > +// { dg-final { scan-assembler-not "_ZN1BD0Ev" } } > +// { dg-final { scan-ipa-dump "Target is artificial" "devirt" } } > +// { dg-final { cleanup-ipa-dump "devirt" } }