Patchwork Fix debug info of nested inline functions

login
register
mail settings
Submitter Eric Botcazou
Date Sept. 15, 2010, 10 p.m.
Message ID <201009160000.41986.ebotcazou@adacore.com>
Download mbox | patch
Permalink /patch/64915/
State New
Headers show

Comments

Eric Botcazou - Sept. 15, 2010, 10 p.m.
> OK.  I would expect DECL_ABSTRACT (current_function_decl) to be set
> whenever DECL_ABSTRACT (decl) is set, but I guess it doesn't hurt to
> check both.

Yes, that works fine.

> > This hunk is necessary to prevent abstracted nested functions from being
> > emitted twice in the enclosing function if they are inlined there, as a
> > concrete inline and as a concrete out-of-line instance.  We wait until
> > after actual instances, either inline or out-of-line, are encountered and
> > attach the DIEs in dwarf2out_finish.
>
> OK, I see.

I actually got back to the original big testcase I have and, upon re-analyzing 
it, found out that the first part of the condition is useless.  Only the 
second part:

+  /* Do not emit concrete instances of abstracted nested functions without
+     actual instances.  */
+  else if (TREE_CODE (decl_or_origin) == FUNCTION_DECL
+	   && die
+	   && get_AT (die, DW_AT_inline))
+    ;

does prevent duplicated entries.

> > Yes, the not always fulfilled 4. I mentioned in the message.  How would
> > you do that?  If you look up the DIE of the enclosing function, you get
> > the abstract instance.  The parent of concrete instances doesn't seem to
> > really matter to GDB as long as it isn't abstract.
>
> It seems like the later block that checks DECL_CONTEXT
> (node->created_for) should handle the case of a concrete non-inlined
> instance.

Of a concrete out-of-inline instance of nested functions?  Not in all cases: 
if the parent is also inlined/abstracted, the lookup will return the abstract 
instance of the parent.  This will work if the parent is a regular function, 
in which case the unmodified code using DW_AT_abstract_origin already works.
Jason Merrill - Sept. 15, 2010, 10:14 p.m.
On 09/15/2010 06:00 PM, Eric Botcazou wrote:
>>> Yes, the not always fulfilled 4. I mentioned in the message.  How would
>>> you do that?  If you look up the DIE of the enclosing function, you get
>>> the abstract instance.  The parent of concrete instances doesn't seem to
>>> really matter to GDB as long as it isn't abstract.
>>
>> It seems like the later block that checks DECL_CONTEXT
>> (node->created_for) should handle the case of a concrete non-inlined
>> instance.
>
> Of a concrete out-of-inline instance of nested functions?  Not in all cases:
> if the parent is also inlined/abstracted, the lookup will return the abstract
> instance of the parent.  This will work if the parent is a regular function,
> in which case the unmodified code using DW_AT_abstract_origin already works.

Sure, I guess lookup_decl_die (DECL_CONTEXT (node->created_for)) would 
be the abstract instance if there is no concrete out-of-line instance. 
But if there is an out-of-line instance, won't lookup_decl_die give 
that?  If so, that should be more correct than just walking up 
die_parent.  If it returns the abstract instance, we can walk up 
DECL_CONTEXT and try again.

Jason

Patch

Index: dwarf2out.c
===================================================================
--- dwarf2out.c	(revision 164211)
+++ dwarf2out.c	(working copy)
@@ -18668,7 +18668,13 @@  gen_subprogram_die (tree decl, dw_die_re
   tree fn_arg_types;
   tree outer_scope;
   dw_die_ref old_die = lookup_decl_die (decl);
-  int declaration = (current_function_decl != decl
+  /* Emit an abstract instance of nested functions within an abstract instance
+     of their parent.  */
+  int declaration = ((decl != current_function_decl
+		      && !(DECL_INITIAL (decl) != NULL_TREE
+			   && DECL_ABSTRACT (decl)
+			   && current_function_decl
+			   && DECL_ABSTRACT (current_function_decl)))
 		     || class_or_namespace_scope_p (context_die));
 
   premark_used_types ();
@@ -19446,6 +19452,8 @@  gen_inlined_subroutine_die (tree stmt, d
   gcc_assert (! BLOCK_ABSTRACT (stmt));
 
   decl = block_ultimate_origin (stmt);
+  if (DECL_IGNORED_P (decl))
+    return;
 
   /* Emit info for the abstract instance first, if we haven't yet.  We
      must emit this even if the block is abstract, otherwise when we
@@ -20224,8 +20232,25 @@  gen_block_die (tree stmt, dw_die_ref con
     decls_for_scope (stmt, context_die, depth);
 }
 
+/* Return true if an abstract instance of function DECL can be generated in
+   the debug information.  */
+
+static bool
+function_possibly_abstracted_p (tree decl)
+{
+  while (decl)
+    {
+      if (cgraph_function_possibly_inlined_p (decl))
+	return true;
+      decl = decl_function_context (decl);
+    }
+
+  return false;
+}
+
 /* Process variable DECL (or variable with origin ORIGIN) within
    block STMT and add it to CONTEXT_DIE.  */
+
 static void
 process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
 {
@@ -20243,8 +20268,15 @@  process_scope_var (tree stmt, tree decl,
   if (die != NULL && die->die_parent == NULL)
     add_child_die (context_die, die);
   else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
-    dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+    dwarf2out_imported_module_or_decl_1 (decl_or_origin,
+					 DECL_NAME (decl_or_origin),
 					 stmt, context_die);
+  /* Do not emit concrete instances of abstracted nested functions without
+     actual instances.  */
+  else if (TREE_CODE (decl_or_origin) == FUNCTION_DECL
+	   && die
+	   && get_AT (die, DW_AT_inline))
+    ;
   else
     gen_decl_die (decl, origin, context_die);
 }
@@ -20584,11 +20616,11 @@  gen_decl_die (tree decl, tree origin, dw
 				     ? DECL_ORIGIN (origin)
 				     : DECL_ABSTRACT_ORIGIN (decl));
 
-      /* If we're emitting an out-of-line copy of an inline function,
+      /* If we're emitting an out-of-line copy of an abstracted function,
 	 emit info for the abstract instance and set up to refer to it.  */
-      else if (cgraph_function_possibly_inlined_p (decl)
-	       && ! DECL_ABSTRACT (decl)
-	       && ! class_or_namespace_scope_p (context_die)
+      else if (!DECL_ABSTRACT (decl)
+	       && function_possibly_abstracted_p (decl)
+	       && !class_or_namespace_scope_p (context_die)
 	       /* dwarf2out_abstract_function won't emit a die if this is just
 		  a declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
 		  that case, because that works only if we have a die.  */
@@ -22361,7 +22393,18 @@  dwarf2out_finish (const char *filename)
 	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
 
 	  if (origin)
-	    add_child_die (origin->die_parent, die);
+	    {
+	      /* Find the first non-abstract parent instance.  */
+	      do
+		origin = origin->die_parent;
+	      while (origin
+		     && (origin->die_tag != DW_TAG_subprogram
+			 || get_AT (origin, DW_AT_inline)));
+	      if (origin)
+		add_child_die (origin, die);
+	      else
+		add_child_die (comp_unit_die, die);
+	    }
 	  else if (die == comp_unit_die)
 	    ;
 	  else if (seen_error ())