https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86208
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jason at gcc dot gnu.org, | |nathan at gcc dot gnu.org --- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> --- The reason why it worked in 3.2 is I think the keeping of inline function bodies was keyed on TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) at those times, so when emitting assembly for the main function TREE_SYMBOL_REFERENCE has been set and when checking up deferred_fns later on the function was seen as DECL_NEEDED_P. Seems contemporary gcc replaces the call to the local extern decl with the actual inline fn definition in: /* Map block scope extern declarations to visible declarations with the same name and type in outer scopes if any. */ if (cp_function_chain->extern_decl_map && VAR_OR_FUNCTION_DECL_P (stmt) && DECL_EXTERNAL (stmt)) { struct cxx_int_tree_map *h, in; in.uid = DECL_UID (stmt); h = cp_function_chain->extern_decl_map->find_with_hash (&in, in.uid); if (h) { *stmt_p = h->to; *walk_subtrees = 0; return NULL; } } Now, if I do e.g. TREE_USED (h->to) |= TREE_USED (stmt);, the textcase works. Not really sure if we should call mark_used here instead, or if e.g. mark_used should use the cp_function_chain->extern_decl_map and mark not just the symbol itself, but the hash table h->to too, whatever. I guess it matters e.g. for deprecated attribute, if we have: __attribute__((deprecated ("foo"))) void foo () {} void bar () { extern void foo (); foo (); } do we want to warn or not?