I'm committing this patch to fix a problem with -fdebug-types-section where some types that have contain nested type templates or member function templates are given different type signatures in different compilation units, depending on which instantiations of those members are contained in the compilation unit. The problem is two-fold:
(1) When moving a type to its own type unit, nested template instantiations shouldn't appear at all as children of the type in the type unit. The skeleton declaration tree left behind in the CU, however, may still need declarations of those instantiations -- for example, if there's an instantiated member function template, the CU will need a DW_TAG_subprogram DIE at the top level, with DW_AT_specification pointing to its declaration inside the skeleton for the class. (2) When computing the type signature, we want to ignore instantiations. For nested instantiated type templates, I solve this by calling break_out_comdat_types recursively before computing the type signature instead of later. For instantiated member function templates, I simply ignore them during the signature computation, since they don't get moved back to the CU until after the signature computation. Bootstrapped and tested with GCC and GDB test suites. -cary 2013-07-26 Cary Coutant <ccout...@google.com> gcc/ * dwarf2out.c (die_checksum_ordered): Don't include template instantiations in signature. (is_template_parameter): New function. (is_template_instantiation): New function. (generate_skeleton_bottom_up): Don't include template instantiations in type unit DIE. (generate_skeleton): Likewise. (break_out_comdat_types): Move recursive call to break out nested types earlier. (prune_unused_types_mark_generic_parms_dies): Call is_template_parameter. Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 201271) +++ gcc/dwarf2out.c (working copy) @@ -3023,6 +3023,7 @@ static void compute_section_prefix (dw_d static int is_type_die (dw_die_ref); static int is_comdat_die (dw_die_ref); static int is_symbol_die (dw_die_ref); +static inline bool is_template_instantiation (dw_die_ref); static void assign_symbol_names (dw_die_ref); static void break_out_includes (dw_die_ref); static int is_declaration_die (dw_die_ref); @@ -6077,22 +6078,29 @@ die_checksum_ordered (dw_die_ref die, st CHECKSUM_ATTR (attrs.at_type); CHECKSUM_ATTR (attrs.at_friend); - /* Checksum the child DIEs, except for nested types and member functions. */ + /* Checksum the child DIEs. */ c = die->die_child; if (c) do { dw_attr_ref name_attr; c = c->die_sib; name_attr = get_AT (c, DW_AT_name); - if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram) - && name_attr != NULL) + if (is_template_instantiation (c)) { + /* Ignore instantiations of member type and function templates. */ + } + else if (name_attr != NULL + && (is_type_die (c) || c->die_tag == DW_TAG_subprogram)) + { + /* Use a shallow checksum for named nested types and member + functions. */ CHECKSUM_ULEB128 ('S'); CHECKSUM_ULEB128 (c->die_tag); CHECKSUM_STRING (AT_string (name_attr)); } else { + /* Use a deep checksum for other children. */ /* Mark this DIE so it gets processed when unmarking. */ if (c->die_mark == 0) c->die_mark = -1; @@ -6505,6 +6513,36 @@ is_class_die (dw_die_ref c) || c->die_tag == DW_TAG_structure_type); } +/* Return non-zero if this DIE is a template parameter. */ + +static inline bool +is_template_parameter (dw_die_ref die) +{ + switch (die->die_tag) + { + case DW_TAG_template_type_param: + case DW_TAG_template_value_param: + case DW_TAG_GNU_template_template_param: + case DW_TAG_GNU_template_parameter_pack: + return true; + default: + return false; + } +} + +/* Return non-zero if this DIE represents a template instantiation. */ + +static inline bool +is_template_instantiation (dw_die_ref die) +{ + dw_die_ref c; + + if (!is_type_die (die) && die->die_tag != DW_TAG_subprogram) + return false; + FOR_EACH_CHILD (die, c, if (is_template_parameter (c)) return true); + return false; +} + static char * gen_internal_sym (const char *prefix) { @@ -7064,17 +7102,30 @@ generate_skeleton_bottom_up (skeleton_ch node.new_die = NULL; if (is_declaration_die (c)) { - /* Clone the existing DIE, move the original to the skeleton - tree (which is in the main CU), and put the clone, with - all the original's children, where the original came from. */ - dw_die_ref clone = clone_die (c); - move_all_children (c, clone); - - replace_child (c, clone, prev); - generate_skeleton_ancestor_tree (parent); - add_child_die (parent->new_die, c); - node.new_die = c; - c = clone; + if (is_template_instantiation (c)) + { + /* Instantiated templates do not need to be cloned into the + type unit. Just move the DIE and its children back to + the skeleton tree (in the main CU). */ + remove_child_with_prev (c, prev); + add_child_die (parent->new_die, c); + c = prev; + } + else + { + /* Clone the existing DIE, move the original to the skeleton + tree (which is in the main CU), and put the clone, with + all the original's children, where the original came from + (which is about to be moved to the type unit). */ + dw_die_ref clone = clone_die (c); + move_all_children (c, clone); + + replace_child (c, clone, prev); + generate_skeleton_ancestor_tree (parent); + add_child_die (parent->new_die, c); + node.new_die = c; + c = clone; + } } generate_skeleton_bottom_up (&node); } while (next != NULL); @@ -7092,8 +7143,11 @@ generate_skeleton (dw_die_ref die) node.parent = NULL; /* If this type definition is nested inside another type, - always leave at least a declaration in its place. */ - if (die->die_parent != NULL && is_type_die (die->die_parent)) + and is not an instantiation of a template, always leave + at least a declaration in its place. */ + if (die->die_parent != NULL + && is_type_die (die->die_parent) + && !is_template_instantiation (die)) node.new_die = clone_as_declaration (die); generate_skeleton_bottom_up (&node); @@ -7168,6 +7222,9 @@ break_out_comdat_types (dw_die_ref die) dw_die_ref replacement; comdat_type_node_ref type_node; + /* Break out nested types into their own type units. */ + break_out_comdat_types (c); + /* Create a new type unit DIE as the root for the new tree, and add it to the list of comdat types. */ unit = new_die (DW_TAG_type_unit, NULL, NULL); @@ -7187,9 +7244,6 @@ break_out_comdat_types (dw_die_ref die) replacement = remove_child_or_replace_with_skeleton (unit, c, prev); type_node->skeleton_die = replacement; - /* Break out nested types into their own type units. */ - break_out_comdat_types (c); - /* Add the DIE to the new compunit. */ add_child_die (unit, c); @@ -22142,17 +22196,8 @@ prune_unused_types_mark_generic_parms_di c = die->die_child; do { - switch (c->die_tag) - { - case DW_TAG_template_type_param: - case DW_TAG_template_value_param: - case DW_TAG_GNU_template_template_param: - case DW_TAG_GNU_template_parameter_pack: - prune_unused_types_mark (c, 1); - break; - default: - break; - } + if (is_template_parameter (c)) + prune_unused_types_mark (c, 1); c = c->die_sib; } while (c && c != die->die_child); }