PR ipa/58585 (virtual inheritance ICE)

Jan Hubicka
Fri Jan 10 21:40:00 GMT 2014

this patch fixes checking ICE in the attached testcase that happens because we end up
devirtualizing into a function that is not withing possible polymorphic call target.
The defauled analysis is in the PR and also in comment bellow.  The basic problem
is that we build type inheritance tree starting from virtual methods assuming that
we only need polymorphic types with methods defined in it.

This is not completely the case for virtual inheritance, where the class itself
uses a method, but derived classes (not having virtual methods themselves) may
use a virtual thunk.

This patch completes the hiearchy by looking for virtual tables defined.  This
is still not 100% sure since we may forget enlisting virtual thunks used from
other file, but since in that case the thunks needs to be exported our standard
visibility code will handle it.

Bootstrapped/regtested x86_64-linux.
	PR ipa/58585
	* ipa-devirt.c (build_type_inheritance_graph): Also add types of vtables
	into the type inheritance graph.

	* g++.dg/torture/pr58585.C: New testcase.
Index: ipa-devirt.c
--- ipa-devirt.c	(revision 206516)
+++ ipa-devirt.c	(working copy)
@@ -542,7 +542,7 @@ method_class_type (tree t)
 build_type_inheritance_graph (void)
-  struct cgraph_node *n;
+  struct symtab_node *n;
   FILE *inheritance_dump_file;
   int flags;
@@ -554,10 +554,37 @@ build_type_inheritance_graph (void)
   /* We reconstruct the graph starting of types of all methods seen in the
      the unit.  */
-    if (DECL_VIRTUAL_P (n->decl)
+    if (is_a <cgraph_node> (n)
+	&& DECL_VIRTUAL_P (n->decl)
 	&& symtab_real_symbol_p (n))
       get_odr_type (method_class_type (TREE_TYPE (n->decl)), true);
+    /* Look also for virtual tables of types that do not define any methods.
+       We need it in a case where class B has virtual base of class A
+       re-defining its virtual method and there is class C with no virtual
+       methods with B as virtual base.
+       Here we output B's virtual method in two variant - for non-virtual
+       and virtual inheritance.  B's virtual table has non-virtual version,
+       while C's has virtual.
+       For this reason we need to know about C in order to include both
+       variants of B.  More correctly, record_target_from_binfo should
+       add both variants of the method when walking B, but we have no
+       link in between them.
+       We rely on fact that either the method is exported and thus we
+       assume it is called externally or C is in anonymous namespace and
+       thus we will see the vtable.  */
+    else if (is_a <varpool_node> (n)
+	     && DECL_VIRTUAL_P (n->decl)
+	     && TREE_CODE (DECL_CONTEXT (n->decl)) == RECORD_TYPE
+	     && TYPE_BINFO (DECL_CONTEXT (n->decl))
+	     && polymorphic_type_binfo_p (TYPE_BINFO (DECL_CONTEXT (n->decl))))
+      get_odr_type (DECL_CONTEXT (n->decl), true);
   if (inheritance_dump_file)
       dump_type_inheritance_graph (inheritance_dump_file);
Index: testsuite/g++.dg/torture/pr58585.C
--- testsuite/g++.dg/torture/pr58585.C	(revision 0)
+++ testsuite/g++.dg/torture/pr58585.C	(working copy)
@@ -0,0 +1,20 @@
+// { dg-do compile }
+// { dg-options "-fpic" { target fpic } }
+struct A
+  virtual void foo() {}
+  void bar();
+void A::bar() { foo(); }
+struct B : virtual A
+  virtual void foo() {}
+  char c;
+struct C : virtual B
+  C();
+C::C() { bar(); }

More information about the Gcc-patches mailing list