PR c++/22592

Jan Hubicka jh@suse.cz
Fri Sep 2 16:34:00 GMT 2005


Hi,
the following testcase:
struct A {
  virtual bool operator== (const A &a) const;
  virtual bool operator!= (const A &a) const;
};
inline bool A::operator!= ( const A &a) const
 { return !(*this == a); }
bool breakme(const A& newPath, A &b)
 { return A(newPath) != b; }

Results in comdat+linkonce opreator!= being called dirrectly but it's
out-of-line copy not emit in current compilation unit.  This happens because at
cgraph building time the operator is called via virtual table and the table is
not emit in the current compilation unit and thus the function body is
elliminated as unreachable.  This ususally works (since the out of line copy
will be emit together with the virutal table.

It however break with -fvisibility-inlines-hidden where the out-of-line copy
resist in different DSO as the relocation emit expect function to be defined in
the same DSO.

The situation is somewhat confusing here (at least to me).  I don't think
cgraph can behave more sanely as emitting out-of-line copies of all functions
that might end up referneced after optimizing other virtual calls seems way to
the hell.  (Of course we can do a lot better with early optimization and
devirtualization performed at cgraph building time, we just are not there yet),
so the only sollution is to avoid the optimization from happening.

In general it seems to me that it might be unsafe to fold virtual call to any
COMDAT function that is not reachable otherwise at cgraph construction time,
but unless the (language standard breaking and thus prety dangerous anyway)
-fvisibility-inlines-hidden is used this is pretty harmless and I am not sure
how important this optimization would be.  The patch bellow takes more cureful
approach disabling the transformation only for this parituclar case where
-fvisibility-inlines-hidden takes place, but perhaps removing
(visibility_options.inlines_hidden && DECL_INLINE (fndecl) && DECL_VISIBILITY
(fndecl) == VISIBILITY_HIDDEN) portion of the conditional and caring all
comdats is proper fix?

Bootstrapped/regtested i686-pc-gnu-linux.
and my thanks to Michael for helping me to figure out what really goes
on in this mess ;))
Honza

2005-09-02  Jan Hubicka  <jh@suse.cz>
	PR C++/22592
	* cp/class.c (cp_fold_obj_type_ref): Avoid folding when doing so would
	bring comdat function previously elliminated called directly.
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.731
diff -c -3 -p -r1.731 class.c
*** cp/class.c	15 Aug 2005 20:38:13 -0000	1.731
--- cp/class.c	1 Sep 2005 20:34:27 -0000
*************** cp_fold_obj_type_ref (tree ref, tree kno
*** 7690,7695 ****
--- 7690,7708 ----
  
    cgraph_node (fndecl)->local.vtable_method = true;
  
+   /* For hidden inline comdat functions we must emit out-of-line copy
+      when called dirrectly (as the function might be emit out-of-line and hidden
+      in other DSO where virtual table is defined).  Check that either cgraph
+      information is not finalized yet or that the function is available for other
+      reasons.  */
+   if (visibility_options.inlines_hidden
+       && DECL_INLINE (fndecl)
+       && DECL_VISIBILITY (fndecl) == VISIBILITY_HIDDEN
+       && DECL_COMDAT (fndecl)
+       && cgraph_global_info_ready
+       && !cgraph_node (fndecl)->reachable)
+     return NULL;
+ 
    return build_address (fndecl);
  }
  



More information about the Gcc-patches mailing list