This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[google/gcc-4_8] Fix problem with type signatures and template instantiations.


This patch is for the google/gcc-4_8 branch. I will also submit this
to trunk separately.

This fixes 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.

Google ref b/9884815.


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.

testsuite/
	* g++.dg/debug/dwarf2/dwarf4-nested.C: Update test case.


Index: testsuite/g++.dg/debug/dwarf2/dwarf4-nested.C
===================================================================
--- testsuite/g++.dg/debug/dwarf2/dwarf4-nested.C	(revision 201268)
+++ testsuite/g++.dg/debug/dwarf2/dwarf4-nested.C	(working copy)
@@ -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
Index: dwarf2out.c
===================================================================
--- dwarf2out.c	(revision 201268)
+++ dwarf2out.c	(working copy)
@@ -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);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]