Message ID | 201007280822.00800.ebotcazou@adacore.com |
---|---|
State | New |
Headers | show |
On 07/28/2010 02:22 AM, Eric Botcazou wrote: > + int declaration = ((decl != current_function_decl > + && !(DECL_INITIAL (decl) > + && current_function_decl > + && DECL_ABSTRACT (current_function_decl))) This doesn't seem to depend on decl being nested in current_function_decl, so I'm concerned about it getting the wrong answer if we somehow call gen_subprogram_die for a non-nested function. Does it work to check DECL_ABSTRACT (decl) rather than DECL_ABSTRACT (current_function_decl)? > + /* Do not emit concrete instances of abstracted nested functions without > + actual instances. */ > + else if (TREE_CODE (decl_or_origin) == FUNCTION_DECL > + && ((!DECL_ABSTRACT (decl_or_origin) > + && function_possibly_abstracted_p (decl_or_origin)) > + || (die && get_AT (die, DW_AT_inline)))) > + ; This seems wrong. We do want to emit concrete instances of abstracted nested functions, just not within the abstract instance of the enclosing function. > 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); > + } Here, shouldn't the parent of the concrete instance of the nested function be the concrete instance of the enclosing function? Jason
> > + int declaration = ((decl != current_function_decl > > + && !(DECL_INITIAL (decl) > > + && current_function_decl > > + && DECL_ABSTRACT (current_function_decl))) > > This doesn't seem to depend on decl being nested in > current_function_decl, so I'm concerned about it getting the wrong > answer if we somehow call gen_subprogram_die for a non-nested function. > > Does it work to check DECL_ABSTRACT (decl) rather than DECL_ABSTRACT > (current_function_decl)? We can test the flag on both DECLs to match the comment: /* 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)); > > + /* Do not emit concrete instances of abstracted nested functions > > without + actual instances. */ > > + else if (TREE_CODE (decl_or_origin) == FUNCTION_DECL > > + && ((!DECL_ABSTRACT (decl_or_origin) > > + && function_possibly_abstracted_p (decl_or_origin)) > > + || (die && get_AT (die, DW_AT_inline)))) > > + ; > > This seems wrong. We do want to emit concrete instances of abstracted > nested functions, just not within the abstract instance of the enclosing > function. 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. > > 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); > > + } > > Here, shouldn't the parent of the concrete instance of the nested > function be the concrete instance of the enclosing function? 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.
On 09/10/2010 11:54 AM, Eric Botcazou wrote: > We can test the flag on both DECLs to match the comment: > > /* 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)); 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. >>> + /* Do not emit concrete instances of abstracted nested functions without >>> + actual instances. */ >>> + else if (TREE_CODE (decl_or_origin) == FUNCTION_DECL >>> + && ((!DECL_ABSTRACT (decl_or_origin) >>> + && function_possibly_abstracted_p (decl_or_origin)) >>> + || (die && get_AT (die, DW_AT_inline)))) >>> + ; >> >> This seems wrong. We do want to emit concrete instances of abstracted >> nested functions, just not within the abstract instance of the enclosing >> function. > > 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. >>> 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); >>> + } >> >> Here, shouldn't the parent of the concrete instance of the nested >> function be the concrete instance of the enclosing function? > > 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. Jason
Index: dwarf2out.c =================================================================== --- dwarf2out.c (revision 162566) +++ dwarf2out.c (working copy) @@ -18570,7 +18570,12 @@ 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) + && current_function_decl + && DECL_ABSTRACT (current_function_decl))) || class_or_namespace_scope_p (context_die)); premark_used_types (); @@ -19352,6 +19357,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 @@ -20128,8 +20135,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) { @@ -20147,8 +20171,16 @@ 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 + && ((!DECL_ABSTRACT (decl_or_origin) + && function_possibly_abstracted_p (decl_or_origin)) + || (die && get_AT (die, DW_AT_inline)))) + ; else gen_decl_die (decl, origin, context_die); } @@ -20486,11 +20518,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. */ @@ -22253,7 +22285,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 ())