This patch is for trunk and the google/gcc-4_7 branch. When a class template instantiation is moved into a separate type unit, it can bring along a lot of other referenced types into the type unit, especially if the template is derived from another (large) type that does not have an actually have a type definition in a type unit of its own. When there are many instantiations of the same template, we get a lot of duplication, and in the worst case (a template with several parameters, instantiated multiple times along each dimension), GCC can end up taking a long time and exhausting available memory.
This combinatorial explosion is being caused by copy_decls_walk, where it finds a type DIE that is referenced by the type unit, but is not itself a type unit, and copies a declaration for that type into the type unit in order to resolve the reference within the type unit. In the process, copy_decls_walk also copies all of the children of that DIE. In the case of a base class with member function templates, every one of the instantiated member functions is copied into every type unit that references the base class. I don't believe that it's necessary to copy the children of the class declaration at all, and this patch simply removes the code that copies those children. If there's a reference in the type unit to one of the children of that class, that one child will get copied in as needed. Bootstraps and passes regression tests. Also tested with a large internal test case that previously resulted in out-of-memory during compilation. Google ref b/7041390. 2012-08-28 Cary Coutant <ccout...@google.com> * gcc/dwarf2out.c (clone_tree_partial): Remove. (copy_decls_walk): Don't copy children of a declaration into a type unit. Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 190681) +++ gcc/dwarf2out.c (working copy) @@ -7745,40 +7745,6 @@ copy_ancestor_tree (dw_die_ref unit, dw_ return copy; } -/* Like clone_tree, but copy DW_TAG_subprogram DIEs as declarations. - Enter all the cloned children into the hash table decl_table. */ - -static dw_die_ref -clone_tree_partial (dw_die_ref die, htab_t decl_table) -{ - dw_die_ref c; - dw_die_ref clone; - struct decl_table_entry *entry; - void **slot; - - if (die->die_tag == DW_TAG_subprogram) - clone = clone_as_declaration (die); - else - clone = clone_die (die); - - slot = htab_find_slot_with_hash (decl_table, die, - htab_hash_pointer (die), INSERT); - /* Assert that DIE isn't in the hash table yet. If it would be there - before, the ancestors would be necessarily there as well, therefore - clone_tree_partial wouldn't be called. */ - gcc_assert (*slot == HTAB_EMPTY_ENTRY); - entry = XCNEW (struct decl_table_entry); - entry->orig = die; - entry->copy = clone; - *slot = entry; - - if (die->die_tag != DW_TAG_subprogram) - FOR_EACH_CHILD (die, c, - add_child_die (clone, clone_tree_partial (c, decl_table))); - - return clone; -} - /* Walk the DIE and its children, looking for references to incomplete or trivial types that are unmarked (i.e., that are not in the current type_unit). */ @@ -7826,11 +7792,6 @@ copy_decls_walk (dw_die_ref unit, dw_die entry->copy = copy; *slot = entry; - FOR_EACH_CHILD (targ, c, - add_child_die (copy, - clone_tree_partial (c, - decl_table))); - /* Make sure the cloned tree is marked as part of the type unit. */ mark_dies (copy);