https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66223
--- Comment #8 from Jan Hubicka <hubicka at gcc dot gnu.org> --- Well, if you rely on undefined behaviour, you should not be surprised when your program breaks with optimization. I am testing the following patch: Index: ipa-devirt.c =================================================================== --- ipa-devirt.c (revision 232555) +++ ipa-devirt.c (working copy) @@ -2326,6 +2326,14 @@ referenced_from_vtable_p (struct cgraph_ } return found; } +static bool +is_cxa_pure_virtual_p (tree target) +{ + return target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE + && DECL_NAME (target) + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (target)), + "__cxa_pure_virtual"); +} /* If TARGET has associated node, record it in the NODES array. CAN_REFER specify if program can refer to the target directly. @@ -2341,11 +2349,12 @@ maybe_record_node (vec <cgraph_node *> & { struct cgraph_node *target_node, *alias_target; enum availability avail; + bool pure_virtual = is_cxa_pure_virtual_p (target); - /* cxa_pure_virtual and __builtin_unreachable do not need to be added into + /* __builtin_unreachable do not need to be added into list of targets; the runtime effect of calling them is undefined. Only "real" virtual methods should be accounted. */ - if (target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE) + if (target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE && !pure_virtual) return; if (!can_refer) @@ -2388,6 +2397,7 @@ maybe_record_node (vec <cgraph_node *> & ??? Maybe it would make sense to be more aggressive for LTO even elsewhere. */ if (!flag_ltrans + && !pure_virtual && type_in_anonymous_namespace_p (DECL_CONTEXT (target)) && (!target_node || !referenced_from_vtable_p (target_node))) @@ -2401,6 +2411,20 @@ maybe_record_node (vec <cgraph_node *> & { gcc_assert (!target_node->global.inlined_to); gcc_assert (target_node->real_symbol_p ()); + /* Only add pure virtual if it is the only possible target. This way + we will preserve the diagnostics about pure virtual called in many + cases without disabling optimization in other. */ + if (pure_virtual) + { + if (nodes.length ()) + return; + } + /* If we found a real target, take away cxa_pure_virtual. */ + else if (!pure_virtual && nodes.length () == 1 + && is_cxa_pure_virtual_p (nodes[0]->decl)) + nodes.pop (); + if (pure_virtual && nodes.length ()) + return; if (!inserted->add (target)) { cached_polymorphic_call_targets->add (target_node); which attempts to preserve the call to cxa_pure_virtual in cases it is cheap to do so (i.e. we know it is the only target of the call). It is still more expensive to call cxa_pure_virtual compared to bulitin_unreachable. I will try to get some stats on firefox how often it matters in practice.