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 <ebotca...@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); } }