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]

[3.4 PATCH] PR debug/16261


Hi,

This patch backports enough of Devang's mainline patch to fix the problem on 
the 3.4 branch.  The compiler aborts in dwarf2out.c:output_die here:

	case dw_val_class_die_ref:
	  if (AT_ref_external (a))
	    {
	      char *sym = AT_ref (a)->die_symbol;

	      if (sym == 0)
		abort ();
	      dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, "%s", name);
	    }
	  else if (AT_ref (a)->die_offset == 0)
--->	    abort ();

on

namespace N
{
  struct A {};
  typedef A B;
}

void foo()
{
  struct C
  {
    C(N::B) {}
  };

  N::B b;
  C c(b);
}

when emitting debug info for the type of the N::B parameter of the C 
constructor: the DW_TAG_typedef DIE for B has a null die_offset.  The problem 
is that this DW_TAG_typedef DIE for B has the DW_TAG_subprogram DIE for C as 
its parent, but the latter has not the former as its child, so the former is 
never emitted.

This happens because gen_subprogram_die is invoked twice for the C 
constructor, once for the declaration (DW_AT_declaration is set) and once for 
an inline definition, in that order.  For the former, gen_formal_types_die is 
invoked and generates and attaches the DW_TAG_typedef.  But for the latter, 
all previous DIE children are first removed from the DIE here:

      /* If the definition comes from the same place as the declaration,
	 maybe use the old DIE.  We always want the DIE for this function
	 that has the *_pc attributes to be under comp_unit_die so the
	 debugger can find it.  We also need to do this for abstract
	 instances of inlines, since the spec requires the out-of-line copy
	 to have the same parent.  For local class methods, this doesn't
	 apply; we just use the old DIE.  */
      if ((old_die->die_parent == comp_unit_die || context_die == NULL)
	  && (DECL_ARTIFICIAL (decl)
	      || (get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
		  && (get_AT_unsigned (old_die, DW_AT_decl_line)
		      == (unsigned) DECL_SOURCE_LINE (decl)))))
	{
	  subr_die = old_die;

	  /* Clear out the declaration attribute and the parm types.  */
	  remove_AT (subr_die, DW_AT_declaration);
	  remove_children (subr_die);

and only the DIEs of the formal parameters are attached, not of the types.

Devang's mainline patch makes it so that only the formal parameters, not 
the types, are removed.  I've backported only the necessary bits.

Bootstrapped/regtested on amd64-mandrake-linux-gnu.


2004-12-05  Eric Botcazou  <ebotcazou@libertysurf.fr>

	PR debug/16261
	Backport from mainline:
	2004-01-27  Devang Patel  <dpatel@apple.com>
	
	* dwarf2out.c: (remove_child_TAG): New function.
	(gen_subprogram_die): Do not remove all children dies while reusing
	declaration die for definition.  Instead, selectively remove only formal
	parameters.


2004-12-05  Eric Botcazou  <ebotcazou@libertysurf.fr>

	* g++.dg/debug/typedef2.C: New test.


-- 
Eric Botcazou
Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.478.2.14
diff -u -p -r1.478.2.14 dwarf2out.c
--- dwarf2out.c	25 Oct 2004 21:46:45 -0000	1.478.2.14
+++ dwarf2out.c	2 Dec 2004 14:33:58 -0000
@@ -3649,6 +3649,7 @@ static bool is_java (void);
 static bool is_fortran (void);
 static bool is_ada (void);
 static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
 static inline void free_die (dw_die_ref);
 static void remove_children (dw_die_ref);
 static void add_child_die (dw_die_ref, dw_die_ref);
@@ -5055,6 +5056,34 @@ remove_AT (dw_die_ref die, enum dwarf_at
     }
 }
 
+/* Remove child die whose die_tag is specified tag.  */
+
+static void
+remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
+{
+  dw_die_ref current, prev, next;
+  current = die->die_child;
+  prev = NULL;
+  while (current != NULL)
+    {
+      if (current->die_tag == tag)
+	{
+	  next = current->die_sib;
+	  if (prev == NULL)
+	    die->die_child = next;
+	  else
+	    prev->die_sib = next;
+	  free_die (current);
+	  current = next;
+	}
+      else
+	{
+	  prev = current;
+	  current = current->die_sib;
+	}
+    }
+}
+
 /* Free up the memory used by DIE.  */
 
 static inline void
@@ -10872,9 +10901,9 @@ gen_subprogram_die (tree decl, dw_die_re
 	{
 	  subr_die = old_die;
 
-	  /* Clear out the declaration attribute and the parm types.  */
+	  /* Clear out the declaration attribute and the formal parameters.  */
 	  remove_AT (subr_die, DW_AT_declaration);
-	  remove_children (subr_die);
+	  remove_child_TAG (subr_die, DW_TAG_formal_parameter);
 	}
       else
 	{
// PR debug/16261
// { dg-do compile }

namespace N
{
  struct A {};
  typedef A B;
}

void foo()
{
  struct C
  {
    C(N::B) {}
  };

  N::B b;
  C c(b);
}

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