===================================================================
@@ -8,10 +8,9 @@
//
// { dg-final { scan-assembler "DIE \\(\[^\n\]*\\) DW_TAG_type_unit" } }
//
-// Check that func is declared exactly twice in the debug info:
-// once in the type unit for struct D, and once in the compile unit.
+// Check that func is declared exactly once in the debug info.
//
-// { dg-final { scan-assembler-times "\\.ascii \"func\\\\0\"\[^\n\]*DW_AT_name" 2 } }
+// { dg-final { scan-assembler-times "\\.ascii \"func\\\\0\"\[^\n\]*DW_AT_name" 1 } }
//
// Check to make sure that no type unit contains a DIE with DW_AT_low_pc
// or DW_AT_ranges. These patterns assume that the compile unit is always
===================================================================
@@ -3060,6 +3060,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);
@@ -6120,22 +6121,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;
@@ -6540,6 +6548,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)
{
@@ -7005,23 +7043,36 @@ 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);
-
- /* If the original has a DW_AT_object_pointer attribute,
- it would now point to a child DIE just moved to the
- cloned tree, so we need to remove that attribute from
- the original. */
- remove_AT (c, DW_AT_object_pointer);
-
- 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);
+
+ /* If the original has a DW_AT_object_pointer attribute,
+ it would now point to a child DIE just moved to the
+ cloned tree, so we need to remove that attribute from
+ the original. */
+ remove_AT (c, DW_AT_object_pointer);
+
+ 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);
@@ -7039,8 +7090,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);
@@ -7115,6 +7169,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);
@@ -7134,9 +7191,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);
@@ -22278,17 +22332,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);
}