https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93115
--- Comment #4 from Jan Hubicka <hubicka at gcc dot gnu.org> --- The problem here is that we produce ipa-cp clone to devirtualize v::av which also lead to devirtualization of m::av, but we miss this optimization. After inlining we remove m::av and while producing the ipa-cp clone we devirtualize to it which elads to undefined reference. I am testing the following: Index: ipa.c =================================================================== --- ipa.c (revision 279810) +++ ipa.c (working copy) @@ -187,6 +187,7 @@ walk_polymorphic_call_targets (hash_set< for (i = 0; i < targets.length (); i++) { struct cgraph_node *n = targets[i]; + bool added = false; /* Do not bother to mark virtual methods in anonymous namespace; either we will find use of virtual table defining it, or it is @@ -212,11 +213,18 @@ walk_polymorphic_call_targets (hash_set< && symtab->state < IPA_SSA_AFTER_INLINING) reachable->add (body); reachable->add (n); + added = true; } /* Even after inlining we want to keep the possible targets in the boundary, so late passes can still produce direct call even if - the chance for inlining is lost. */ - enqueue_node (n, first, reachable); + the chance for inlining is lost. + Do not keep references to comdat groups - removing their definition + first and adding references later is going to give undefined + reference errors. */ + if (added || (!DECL_COMDAT (n->decl) + || DECL_EXTERNAL (n->decl) + || !TREE_PUBLIC (n->decl))) + enqueue_node (n, first, reachable); } }