Hi! Long time ago, probably all FEs or most of them emitted an extra BLOCK around the BLOCK corresponding to user scope of the function, then the C FE has been changed not to and no_body_blocks langhook has been added for it (and Java/Ada/Fortran were mishandled), later on r144474 removed the langhook and left C++ broken.
As the testcase shows, this is not only unnecessary increase in debug info size (0.5% on cc1plus), but also makes it harder to debug programs, because some variables might appear out of scope on the closing }. This patch tweaks the C++ FE to do what C FE does for 11+ years already, emit the variables in the function scope directly in DW_TAG_subprogram rather than keeping there just the parameters and putting everything else in an artificial DW_TAG_lexical_block. I had to tweak outer_curly_brace_block, so that it would still be able to find the right block with the function scope for FUNCTION_NEEDS_BODY_BLOCK and other functions, if we could avoid the artificial block or not. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2015-02-05 Jakub Jelinek <ja...@redhat.com> PR debug/55541 * cp-tree.h (BLOCK_OUTER_CURLY_BRACE_P): Define. * decl.c (poplevel): If functionbody, try not to create an extra BLOCK for function body and use subblocks as that, if it is non-NULL and doesn't have siblings. Set BLOCK_OUTER_CURLY_BRACE_P flag. (outer_curly_brace_block): Use BLOCK_OUTER_CURLY_BRACE_P flag. * g++.dg/debug/dwarf2/localclass3.C: Adjust for the extraneous DW_TAG_lexical_block removal. * g++.dg/debug/dwarf2/redeclaration-1.C: Likewise. * g++.dg/guality/pr55541.C: New test. --- gcc/cp/cp-tree.h.jj 2015-01-15 23:57:07.000000000 +0100 +++ gcc/cp/cp-tree.h 2015-02-05 19:45:35.015905343 +0100 @@ -84,6 +84,7 @@ c-common.h, not after. PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION) TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO) SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR) + BLOCK_OUTER_CURLY_BRACE_P (in BLOCK) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -326,6 +327,9 @@ typedef struct ptrmem_cst * ptrmem_cst_t #define STATEMENT_LIST_TRY_BLOCK(NODE) \ TREE_LANG_FLAG_2 (STATEMENT_LIST_CHECK (NODE)) +/* Mark the outer curly brace BLOCK. */ +#define BLOCK_OUTER_CURLY_BRACE_P(NODE) TREE_LANG_FLAG_0 (BLOCK_CHECK (NODE)) + /* Nonzero if this statement should be considered a full-expression, i.e., if temporaries created during this statement should have their destructors run at the end of this statement. */ --- gcc/cp/decl.c.jj 2015-02-03 10:33:56.000000000 +0100 +++ gcc/cp/decl.c 2015-02-05 21:03:39.851179354 +0100 @@ -610,7 +610,10 @@ poplevel (int keep, int reverse, int fun or if this level is a function body, create a BLOCK to record them for the life of this function. */ block = NULL_TREE; - if (keep == 1 || functionbody) + /* Avoid function body block if possible. */ + if (functionbody && subblocks && BLOCK_CHAIN (subblocks) == NULL_TREE) + keep = 0; + else if (keep == 1 || functionbody) block = make_node (BLOCK); if (block != NULL_TREE) { @@ -793,11 +796,16 @@ poplevel (int keep, int reverse, int fun check over all the labels. */ if (functionbody) { - /* Since this is the top level block of a function, the vars are - the function's parameters. Don't leave them in the BLOCK - because they are found in the FUNCTION_DECL instead. */ - BLOCK_VARS (block) = 0; - pop_labels (block); + if (block) + { + /* Since this is the top level block of a function, the vars are + the function's parameters. Don't leave them in the BLOCK + because they are found in the FUNCTION_DECL instead. */ + BLOCK_VARS (block) = 0; + pop_labels (block); + } + else + pop_labels (subblocks); } kind = current_binding_level->kind; @@ -819,7 +827,17 @@ poplevel (int keep, int reverse, int fun /* The current function is being defined, so its DECL_INITIAL should be error_mark_node. */ gcc_assert (DECL_INITIAL (current_function_decl) == error_mark_node); - DECL_INITIAL (current_function_decl) = block; + DECL_INITIAL (current_function_decl) = block ? block : subblocks; + if (subblocks) + { + if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) + { + if (BLOCK_SUBBLOCKS (subblocks)) + BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1; + } + else + BLOCK_OUTER_CURLY_BRACE_P (subblocks) = 1; + } } else if (block) current_binding_level->blocks @@ -14053,10 +14071,14 @@ finish_function_body (tree compstmt) tree outer_curly_brace_block (tree fndecl) { - tree block = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl)); - if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) - /* Skip the artificial function body block. */ - block = BLOCK_SUBBLOCKS (block); + tree block = DECL_INITIAL (fndecl); + if (BLOCK_OUTER_CURLY_BRACE_P (block)) + return block; + block = BLOCK_SUBBLOCKS (block); + if (BLOCK_OUTER_CURLY_BRACE_P (block)) + return block; + block = BLOCK_SUBBLOCKS (block); + gcc_assert (BLOCK_OUTER_CURLY_BRACE_P (block)); return block; } --- gcc/testsuite/g++.dg/debug/dwarf2/localclass3.C.jj 2012-05-08 14:16:04.000000000 +0200 +++ gcc/testsuite/g++.dg/debug/dwarf2/localclass3.C 2015-02-05 21:49:01.738482422 +0100 @@ -4,8 +4,11 @@ void f() { - struct A { int i; } *ap; - ap->i = 42; + int j = 5; + { + struct A { int i; } *ap; + ap->i = 42; + } } // { dg-final { scan-assembler "DW_TAG_pointer_type.\[^)\]*. DW_TAG_structure_type" } } --- gcc/testsuite/g++.dg/debug/dwarf2/redeclaration-1.C.jj 2010-04-07 13:39:52.000000000 +0200 +++ gcc/testsuite/g++.dg/debug/dwarf2/redeclaration-1.C 2015-02-05 21:57:08.348311646 +0100 @@ -9,10 +9,12 @@ namespace S int f() { - int i = 42; { - extern int i; - return i; + int i = 42; + { + extern int i; + return i; + } } } } --- gcc/testsuite/g++.dg/guality/pr55541.C.jj 2015-02-05 17:13:56.947978046 +0100 +++ gcc/testsuite/g++.dg/guality/pr55541.C 2015-02-05 17:13:34.000000000 +0100 @@ -0,0 +1,11 @@ +// PR debug/55541 +// { dg-do run } +// { dg-options "-g" } + +int +main () +{ + int vari; + vari = 10; + vari = vari + 5; +} // { dg-final { gdb-test 11 "vari" "15" } } Jakub