https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77947
--- Comment #6 from rguenther at suse dot de <rguenther at suse dot de> --- On Wed, 12 Oct 2016, marxin at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77947 > > --- Comment #5 from Martin Liška <marxin at gcc dot gnu.org> --- > Created attachment 39791 > --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=39791&action=edit > Really reduced test-case So we are properly creating a DIE for m_fn1 early but then end up removing it via prune_unused_types. It looks like this is because the DIE for C has the CU as parent rather than B::m_fn2. It first gets created in limbo (via dwarf2out_type_decl) because: /* If we're a function-scope tag, initially use a parent of NULL; this will be fixed up in decls_for_scope. */ if (decl_function_context (decl)) context_die = NULL; but we never end up calling dwarf2out_early_global_decl for B::m_fn2 and thus the limbo gets re-parented to the CU DIE (as we record the TREE_TYPE for DW_TAG_class_type DIEs, not the TYPE_DECL): if (DECL_P (node->created_for)) origin = get_context_die (DECL_CONTEXT (node->created_for)); else if (TYPE_P (node->created_for)) origin = scope_die_for (node->created_for, comp_unit_die ()); and scope_die_for simply doesn't handle FUNCTION_DECL as containing_scope. B::m_fn2 has been optimized out as unreachable which is the reason we are not ending up in decls_for_scope eventually. IMHO optimizing C as unused is ok. The question is why we end up with inlining m_fn1 ... looks like we devirtualize the call in fn1 to B::C::m_fn1: t.ii:25:14: note: speculatively devirtualizing call in void fn1(A&)/8 to virtual bool B::m_fn2() const::C::m_fn1() const/0 Indirect call -> speculative call void fn1(A&)/8 => virtual bool B::m_fn2() const::C::m_fn1() const/0 1 polymorphic calls, 0 devirtualized, 1 speculatively devirtualized, 0 cold 0 have multiple targets, 0 overwritable, 0 already speculated (0 agree, 0 disagree), 0 external, 0 not defined, 0 artificial, 0 infos dropped Symbol table: and -fno-devirtualize fixes it. -> we shouldn't reclaim B::m_fn2 when we later end up devirtualizing to B::m_fn2::C::m_fn1 (or rather we should never devirtualize to a local class method?)