We do not create a DW_AT_lexical_block for the outermost block in functions but we do for DW_AT_inlined_subroutines. That makes debuginfo look like if there were two of each local, the outer one (from the abstract instance) optimized out (visible via info locals in gdb).
The following elides the outermost block also from inline instances. It's a bit tricky to reliably track that block given we remove unused blocks here and there. The trick is to have the block in the abstract instance _not_ point to itself (given we do not output it it isn't the abstract origin for itself). Bootstrapped on x86_64-unkown-linux-gnu, testing in progress. Again with some scan-assembler testcase, guality cannot do 'info locals'. OK? Thanks, Richard. 2018-09-26 Richard Biener <rguent...@suse.de> PR debug/87440 * dwarf2out.c (set_block_origin_self): Do not mark outermost block as we do not output that. (gen_inlined_subroutine_die): Elide the originally outermost block, matching what we do for concrete instances. (decls_for_scope): Add parameter specifying whether to recurse to subblocks. * gcc.dg/debug/dwarf2/inline4.c: New testcase. Index: gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c =================================================================== --- gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c (nonexistent) +++ gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c (working copy) @@ -0,0 +1,17 @@ +/* Verify that the inline instance has no extra DW_TAG_lexical_block between + the DW_TAG_inlined_subroutine and the DW_TAG_variable for the local. */ +/* { dg-options "-O -gdwarf -dA" } */ +/* { dg-do compile } */ +/* { dg-final { scan-assembler "DW_TAG_inlined_subroutine\[^\\(\]*\\(\[^\\)\]*\\)\[^\\(\]*\\(DIE \\(0x\[0-9a-f\]*\\) DW_TAG_formal_parameter\[^\\(\]*\\(DIE \\(0x\[0-9a-f\]*\\) DW_TAG_variable" } } */ +/* { dg-final { scan-assembler-times "DW_TAG_inlined_subroutine" 2 } } */ + +static int foo (int i) +{ + volatile int j = i + 3; + return j - 2; +} +int main() +{ + volatile int z = foo (-1); + return z; +} Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 264640) +++ gcc/dwarf2out.c (working copy) @@ -3867,7 +3867,7 @@ static void gen_subroutine_type_die (tre static void gen_typedef_die (tree, dw_die_ref); static void gen_type_die (tree, dw_die_ref); static void gen_block_die (tree, dw_die_ref); -static void decls_for_scope (tree, dw_die_ref); +static void decls_for_scope (tree, dw_die_ref, bool = true); static bool is_naming_typedef_decl (const_tree); static inline dw_die_ref get_context_die (tree); static void gen_namespace_die (tree, dw_die_ref); @@ -22389,7 +22389,13 @@ set_block_origin_self (tree stmt) { if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE) { - BLOCK_ABSTRACT_ORIGIN (stmt) = stmt; + /* We do not mark the outermost block as we are not outputting it. + This is then a reliable way of determining whether we should + do the same for an inline instance. */ + if (TREE_CODE (BLOCK_SUPERCONTEXT (stmt)) != FUNCTION_DECL) + BLOCK_ABSTRACT_ORIGIN (stmt) = stmt; + else + gcc_assert (DECL_INITIAL (BLOCK_SUPERCONTEXT (stmt)) == stmt); { tree local_decl; @@ -24149,7 +24155,24 @@ gen_inlined_subroutine_die (tree stmt, d add_high_low_attributes (stmt, subr_die); add_call_src_coords_attributes (stmt, subr_die); - decls_for_scope (stmt, subr_die); + /* The inliner creates an extra BLOCK for the parameter setup, + we want to merge that with the actual outermost BLOCK of the + inlined function to avoid duplicate locals in consumers. Note + we specially mark that not as origin-self. + Do that by doing the recursion to subblocks on the single subblock + of STMT. */ + bool unwrap_one = false; + if (BLOCK_SUBBLOCKS (stmt) && !BLOCK_CHAIN (BLOCK_SUBBLOCKS (stmt))) + { + tree origin = block_ultimate_origin (BLOCK_SUBBLOCKS (stmt)); + if (origin + && TREE_CODE (origin) == BLOCK + && !BLOCK_ABSTRACT_ORIGIN (origin)) + unwrap_one = true; + } + decls_for_scope (stmt, subr_die, !unwrap_one); + if (unwrap_one) + decls_for_scope (BLOCK_SUBBLOCKS (stmt), subr_die); } } @@ -25777,7 +25800,7 @@ process_scope_var (tree stmt, tree decl, all of its sub-blocks. */ static void -decls_for_scope (tree stmt, dw_die_ref context_die) +decls_for_scope (tree stmt, dw_die_ref context_die, bool recurse) { tree decl; unsigned int i; @@ -25820,10 +25843,11 @@ decls_for_scope (tree stmt, dw_die_ref c /* Output the DIEs to represent all sub-blocks (and the items declared therein) of this block. */ - for (subblocks = BLOCK_SUBBLOCKS (stmt); - subblocks != NULL; - subblocks = BLOCK_CHAIN (subblocks)) - gen_block_die (subblocks, context_die); + if (recurse) + for (subblocks = BLOCK_SUBBLOCKS (stmt); + subblocks != NULL; + subblocks = BLOCK_CHAIN (subblocks)) + gen_block_die (subblocks, context_die); } /* Is this a typedef we can avoid emitting? */