diff mbox

[Dodji,Seketeli] Fix PR debug/46101

Message ID m3mxpb4vmu.fsf@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli Nov. 14, 2010, 6:18 p.m. UTC
I accidentally sent this patch mail to Jason only.

Re-sending to the list proper.
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.

Comments

Jason Merrill Nov. 24, 2010, 11:35 p.m. UTC | #1
On 11/14/2010 01:18 PM, Dodji Seketeli wrote:
> @@ -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);

This one shouldn't be necessary; you can't have an anonymous class 
template.  Otherwise OK.

Jason
diff mbox

Patch

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;