[patch] Fix problem with -fdebug-types-section and template instantiations.

Cary Coutant ccoutant@google.com
Fri Jul 26 20:00:00 GMT 2013


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  <ccoutant@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);
 }



More information about the Gcc-patches mailing list