This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] Fix debug info of nested inline functions
- From: Eric Botcazou <ebotcazou at adacore dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 2 Mar 2012 21:29:30 +0100
- Subject: [patch] Fix debug info of nested inline functions
Hi Jason,
you may remember a patch I posted and over which we exchanged a few messages:
first message: http://gcc.gnu.org/ml/gcc-patches/2010-07/msg02143.html
last message: http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01289.html
I eventually dropped the ball and nothing was installed, although we had almost
reached an agreement.
The problem is still present as of today on the mainline, so I think now is a
good time to solve it once for all. We were disagreeing on the last hunk of
the latest revision of the patch:
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01286.html
and you suggested to iterate over DECL_CONTEXT instead of die_parent to find an
appropriate parent in order to attach the DIE on the limbo list to.
I confirm that we need to iterate, as the immediate DECL_CONTEXT is an abtract
instance for the testcase. The attached patch implements this and generates
exactly the same debug info for the testcase as the original patch.
Tested on x86_64-suse-linux, OK for the mainline?
2012-03-02 Eric Botcazou <ebotcazou@adacore.com>
* dwarf2out.c (gen_subprogram_die): Emit a definition of nested
functions within an abstract instance of their parent.
(gen_inlined_subroutine_die): Return if the origin is to be ignored.
(function_possibly_abstracted_p): New static function.
(process_scope_var): Do not emit concrete instances of abstracted
nested functions from here.
(gen_decl_die): Emit the abstract instance if the function is possibly
abstracted and not only possibly inlined.
(dwarf2out_finish): Skip an abtract parent instance and iterate over
the context to find the first non-abstract parent instance to attach
concrete instances on the limbo list to it.
--
Eric Botcazou
Index: dwarf2out.c
===================================================================
--- dwarf2out.c (revision 184668)
+++ dwarf2out.c (working copy)
@@ -17173,7 +17173,13 @@ gen_subprogram_die (tree decl, dw_die_re
dw_die_ref subr_die;
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 ();
@@ -18198,6 +18204,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
@@ -19158,8 +19166,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)
{
@@ -19177,8 +19202,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);
}
@@ -19525,11 +19557,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. */
@@ -22526,7 +22558,11 @@ dwarf2out_finish (const char *filename)
{
dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
- if (origin && origin->die_parent)
+ if (origin
+ && origin->die_parent
+ /* Skip an abtract parent instance. */
+ && !(origin->die_parent->die_tag == DW_TAG_subprogram
+ && get_AT (origin->die_parent, DW_AT_inline)))
add_child_die (origin->die_parent, die);
else if (is_cu_die (die))
;
@@ -22545,16 +22581,22 @@ dwarf2out_finish (const char *filename)
inlined and optimized out. In that case we are lost and
assign the empty child. This should not be big issue as
the function is likely unreachable too. */
- tree context = NULL_TREE;
-
- gcc_assert (node->created_for);
+ tree context = node->created_for;
+ gcc_assert (context);
- if (DECL_P (node->created_for))
- context = DECL_CONTEXT (node->created_for);
- else if (TYPE_P (node->created_for))
- context = TYPE_CONTEXT (node->created_for);
+ /* Find the first non-abstract parent instance. */
+ do {
+ if (DECL_P (context))
+ context = DECL_CONTEXT (context);
+ else if (TYPE_P (context))
+ context = TYPE_CONTEXT (context);
+ else
+ context = NULL_TREE;
+ origin = get_context_die (context);
+ } while (origin
+ && origin->die_tag == DW_TAG_subprogram
+ && get_AT (origin, DW_AT_inline));
- origin = get_context_die (context);
add_child_die (origin, die);
}
}