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]

[Dodji Seketeli] Fix PR debug/46101


I accidentally sent this patch mail to Jason only.

Re-sending to the list proper.

--- Begin Message ---
Hello,

Consider this example:

typedef struct
{
  virtual void f () { }
} A;

We create a DW_TAG_typedef for the naming typedef A with a DW_AT_type
attribute pointing to the anonymous struct. In that process we play
trick in gen_typedef_die by associating the type of the anonymous
struct with the DIE of the naming typedef; so that subsequent
lookup_type_die on the anonymous type return the DIE of the naming
typedef.

That trick is fine in most cases, but not in the case that I believe
triggers this ICE.

When callgraph instructs the dwarf backend to emit debug info for f,
the dwarf emitter then does a lookup_type_die on the enclosing struct
of f to hang the DIE of f off the DIE of that enclosing struct of f.

The problem is the result of that lookup_type_die on the anonymous
struct yields the DW_TAG_typedef instead of the DIE of the anonymous
struct. The emitter then tries to hand the DIE of f off of the
DW_TAG_typedef. From that point on, the DIE's graph is corrupted and
weird things happen.

This patch introduces a new function
lookup_type_die_strip_naming_typedef for cases where we want to do
more than just refer to the result of the lookup. Strictly speaking,
it's the hunk below that fixes this present bug:

@@ -18590,7 +18612,7 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
       gcc_assert (!decl_ultimate_origin (member));
 
       push_decl_scope (type);
-      type_die = lookup_type_die (type);
+      type_die = lookup_type_die_strip_naming_typedef (type);
       if (TREE_CODE (member) == FUNCTION_DECL)
 	gen_subprogram_die (member, type_die);
       else if (TREE_CODE (member) == FIELD_DECL)

I looked at all the other uses of lookup_type_die and found out that
some of them silently exhibit the issue. Hence the other hunks.

Tested on x86_64-unknown-linux-gnu against trunk.

-- 
	Dodji

>From d16601c89e153c54ef017cca5db854898d9c6502 Mon Sep 17 00:00:00 2001
From: Dodji Seketeli <dodji@redhat.com>
Date: Sun, 14 Nov 2010 12:55:34 +0100
Subject: [PATCH 1/2] Fix PR debug/46101

gcc/
	* dwarf2out.c (lookup_type_die_strip_naming_typedef): New
	function.
	(gen_generic_params_dies, scope_die_for, gen_type_die_for_member):
	Replace uses of lookup_type_die with use of
	lookup_type_die_strip_naming_typedef.

gcc/testsuite/
	* g++.dg/debug/dwarf2/typedef5.C: New test
---
 gcc/dwarf2out.c                              |   28 +++++++++++++++++++++++--
 gcc/testsuite/g++.dg/debug/dwarf2/typedef5.C |   10 +++++++++
 2 files changed, 35 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/typedef5.C

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 9bb569b..1094a9f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -6160,6 +6160,7 @@ static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
 static void add_child_die (dw_die_ref, dw_die_ref);
 static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
 static dw_die_ref lookup_type_die (tree);
+static dw_die_ref lookup_type_die_strip_naming_typedef (tree);
 static void equate_type_number_to_die (tree, dw_die_ref);
 static hashval_t decl_die_table_hash (const void *);
 static int decl_die_table_eq (const void *, const void *);
@@ -7920,6 +7921,27 @@ lookup_type_die (tree type)
   return TYPE_SYMTAB_DIE (type);
 }
 
+/* Like lookup_type_die, but if type is an anonymous type named by a
+   typedef[1], return the DIE of the anonymous type instead the one of
+   the naming typedef.  This is because in gen_typedef_die, we did
+   equate the anonymous struct named by the typedef with the DIE of
+   the naming typedef. So by default, lookup_type_die on an anonymous
+   struct yields the DIE of the naming typedef.
+
+   [1]: Read the comment of is_naming_typedef_decl to learn about what
+   a naming typedef is.  */
+
+static inline dw_die_ref
+lookup_type_die_strip_naming_typedef (tree type)
+{
+  dw_die_ref die = lookup_type_die (type);
+  if (TREE_CODE (type) == RECORD_TYPE
+      && die->die_tag == DW_TAG_typedef
+      && is_naming_typedef_decl (TYPE_NAME (type)))
+    die = get_AT_ref (die, DW_AT_type);
+  return die;
+}
+
 /* Equate a DIE to a given type specifier.  */
 
 static inline void
@@ -12883,7 +12905,7 @@ gen_generic_params_dies (tree t)
     return;
 
   if (TYPE_P (t))
-    die = lookup_type_die (t);
+    die = lookup_type_die_strip_naming_typedef (t);
   else if (DECL_P (t))
     die = lookup_decl_die (t);
 
@@ -17763,7 +17785,7 @@ scope_die_for (tree t, dw_die_ref context_die)
 	    scope_die = comp_unit_die ();
 	}
       else
-	scope_die = lookup_type_die (containing_scope);
+	scope_die = lookup_type_die_strip_naming_typedef (containing_scope);
     }
   else
     scope_die = context_die;
@@ -18590,7 +18612,7 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
       gcc_assert (!decl_ultimate_origin (member));
 
       push_decl_scope (type);
-      type_die = lookup_type_die (type);
+      type_die = lookup_type_die_strip_naming_typedef (type);
       if (TREE_CODE (member) == FUNCTION_DECL)
 	gen_subprogram_die (member, type_die);
       else if (TREE_CODE (member) == FIELD_DECL)
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/typedef5.C b/gcc/testsuite/g++.dg/debug/dwarf2/typedef5.C
new file mode 100644
index 0000000..d9d058c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/typedef5.C
@@ -0,0 +1,10 @@
+// Origin: PR debug/46101
+// { dg-options "-g -feliminate-dwarf2-dups" }
+// { dg-do compile }
+
+typedef struct
+{
+  virtual void f () { }
+} A;
+
+A a;
-- 
1.7.2.3


--- End Message ---

-- 
	Dodji

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