Patchwork Fix PR debug/45088

login
register
mail settings
Submitter Dodji Seketeli
Date Dec. 14, 2010, 6:26 p.m.
Message ID <m3bp4ow6qh.fsf@redhat.com>
Download mbox | patch
Permalink /patch/75517/
State New
Headers show

Comments

Dodji Seketeli - Dec. 14, 2010, 6:26 p.m.
Jason Merrill <jason@redhat.com> writes:

> On 12/12/2010 10:04 AM, Dodji Seketeli wrote:
>>     /* If TYPE is a typedef type variant, let's generate debug info
>>        for the parent typedef which TYPE is a type of.  */
>> -  if (typedef_variant_p (type))
>> +  if (typedef_variant_p (type)
>> +      &&  !is_redundant_typedef (TYPE_NAME (type)))
>
> I would expect this to cause problems when things use both the main
> type and the injected variant, since the two types have different
> TREE_ASM_WRITTEN.

I see.

>  Rather, if type is a redundant typedef, we should
> strip it to get the underlying type.

Okay, the patch below hopefully does that.

Boostrapped and tested on x86_64-unknown-linux-gnu.
Jason Merrill - Dec. 15, 2010, 2:28 a.m.
On 12/14/2010 01:26 PM, Dodji Seketeli wrote:
> +  if (is_injected_class_name (TYPE_NAME (type)))
> +    type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));

Yes, that should do the trick, but I might still tweak it a bit.

The problematic case is when is_redundant_typedef (decl) && 
DECL_ORIGINAL_TYPE (decl) are both true; gen_decl_die assumes that these 
two conditions can't occur together, which is why things break.  This 
change will make that assumption valid again, but I'd feel better about 
using that condition directly (that is, if (is_redundant_typedef 
(TYPE_NAME (type)) && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) rather than 
assuming that the injected-class-name is the only redundant typedef for 
which this can happen.

I think we should also add an explicit assert to gen_decl_die in the 
is_redundant_typedef case to make sure that DECL_ORIGINAL_TYPE is NULL_TREE.

Jason

Patch

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index c985527..3c9eb95 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -6454,6 +6454,7 @@  static void gen_typedef_die (tree, dw_die_ref);
 static void gen_type_die (tree, dw_die_ref);
 static void gen_block_die (tree, dw_die_ref, int);
 static void decls_for_scope (tree, dw_die_ref, int);
+static bool is_injected_class_name (const_tree decl);
 static int is_redundant_typedef (const_tree);
 static bool is_naming_typedef_decl (const_tree);
 static inline dw_die_ref get_context_die (tree);
@@ -20251,13 +20252,21 @@  gen_tagged_type_die (tree type,
 
 static void
 gen_type_die_with_usage (tree type, dw_die_ref context_die,
-				enum debug_info_usage usage)
+			 enum debug_info_usage usage)
 {
   struct array_descr_info info;
 
   if (type == NULL_TREE || type == error_mark_node)
     return;
 
+  /* The C++ FE uses a special typedef variant to represent the
+     injected-class-name of a type. Letting this through confuses us
+     because we'd consider this typedef as bloat and won't generate
+     debug info for it. What we really want is the underlying type of
+     the injected-class-name.  */
+  if (is_injected_class_name (TYPE_NAME (type)))
+    type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
+
   /* If TYPE is a typedef type variant, let's generate debug info
      for the parent typedef which TYPE is a type of.  */
   if (typedef_variant_p (type))
@@ -20567,6 +20576,22 @@  decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
     gen_block_die (subblocks, context_die, depth + 1);
 }
 
+/* Return TRUE if DECL is a C++ injected-class-name.  */
+
+static inline bool
+is_injected_class_name (const_tree decl)
+{
+  if (is_typedef_decl (CONST_CAST_TREE (decl))
+      && !TYPE_DECL_IS_STUB (decl)
+      && DECL_ARTIFICIAL (decl)
+      && DECL_CONTEXT (decl)
+      && is_tagged_type (DECL_CONTEXT (decl))
+      && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+      && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+    return 1;
+  return 0;
+}
+
 /* Is this a typedef we can avoid emitting?  */
 
 static inline int
@@ -20575,12 +20600,7 @@  is_redundant_typedef (const_tree decl)
   if (TYPE_DECL_IS_STUB (decl))
     return 1;
 
-  if (DECL_ARTIFICIAL (decl)
-      && DECL_CONTEXT (decl)
-      && is_tagged_type (DECL_CONTEXT (decl))
-      && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
-      && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
-    /* Also ignore the artificial member typedef for the class name.  */
+  if (is_injected_class_name (decl))
     return 1;
 
   return 0;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C
new file mode 100644
index 0000000..81bcb27
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C
@@ -0,0 +1,28 @@ 
+// Origin: PR debug/45088
+// { dg-do compile }
+// { dg-options "-g -dA" }
+// { dg-final { scan-assembler-times "\[^\n\r\]*\\(DIE\[^\n\r\]*DW_TAG_pointer_type\\)\[\n\r\]{1,2}\[^\n\r\]*DW_AT_byte_size\[\n\r\]{1,2}\[^\n\r\]*DW_AT_type" 4 } }
+
+struct A
+{
+    virtual ~A();
+};
+
+struct B : public A
+{
+    virtual ~B(){}
+};
+
+struct C : public B
+{
+    A* a1;
+};
+
+int
+main()
+{
+    C c;
+    c.a1 = 0;
+    return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C
new file mode 100644
index 0000000..b1c5401
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C
@@ -0,0 +1,29 @@ 
+// Origin: PR debug/45088
+// { dg-do compile }
+// { dg-options "-g -dA" }
+// { dg-final { scan-assembler-times "\[^\n\r\]*\\(DIE\[^\n\r\]*DW_TAG_pointer_type\\)\[\n\r\]{1,2}\[^\n\r\]*DW_AT_byte_size\[\n\r\]{1,2}\[^\n\r\]*DW_AT_type" 4 } }
+
+template<class T>
+struct A
+{
+    virtual ~A();
+};
+
+struct B : public A<int>
+{
+    virtual ~B(){}
+};
+
+struct C : public B
+{
+    A<int>* a1;
+};
+
+int
+main()
+{
+    C c;
+    c.a1 = 0;
+    return 0;
+}
+