When inlining call stmts with a NULL gimple_block we still remap all the callee blocks into a block tree copy but we'll end up not referencing it from anywhere. This causes verification failures because then we have nothing refering to the inline stmt blocks.
This seems to be an issue mostly with calls created by GCC itself and later via LTO found to have a body and being inlineable. But with the new location block scheme it is a general defect of the inliner (in case we don't want to force all call stmts to have an associated block). The following patch simply arranges for the callee blocks to be remapped to NULL_TREE in the copy in the caller. Another possibility would be to put the remapped block tree into the caller as sibling of its DECL_INITIAL (but that might cause strange scope change artifacts when debugging). A full solution might consist of adding a GIMPLE call stmt flag to tell whether a call is artificial and decide what to do when inlining such calls (the patch fails to re-set the rest of the location info). We'd then verify that all non-artificial calls have an associated block. Sofar very lightly tested (on the testcase in the PR). Jakub, what do you think? Thanks, Richard. 2013-03-04 Richard Biener <rguent...@suse.de> PR lto/56515 * tree-inline.c (remap_blocks_to_null): New function. (expand_call_inline): When expanding a call stmt without an associated block inline remap all callee blocks to NULL. Index: gcc/tree-inline.c =================================================================== *** gcc/tree-inline.c (revision 196423) --- gcc/tree-inline.c (working copy) *************** remap_blocks (tree block, copy_body_data *** 651,656 **** --- 651,666 ---- return new_tree; } + /* Remap the block tree rooted at BLOCK to nothing. */ + static void + remap_blocks_to_null (tree block, copy_body_data *id) + { + tree t; + insert_decl_map (id, block, NULL_TREE); + for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) + remap_blocks_to_null (t, id); + } + static void copy_statement_list (tree *tp) { *************** expand_call_inline (basic_block bb, gimp *** 3909,3919 **** actual inline expansion of the body, and a label for the return statements within the function to jump to. The type of the statement expression is the return type of the function call. */ - id->block = make_node (BLOCK); - BLOCK_ABSTRACT_ORIGIN (id->block) = fn; - BLOCK_SOURCE_LOCATION (id->block) = input_location; if (gimple_block (stmt)) ! prepend_lexical_block (gimple_block (stmt), id->block); /* Local declarations will be replaced by their equivalents in this map. */ --- 3919,3931 ---- actual inline expansion of the body, and a label for the return statements within the function to jump to. The type of the statement expression is the return type of the function call. */ if (gimple_block (stmt)) ! { ! id->block = make_node (BLOCK); ! BLOCK_ABSTRACT_ORIGIN (id->block) = fn; ! BLOCK_SOURCE_LOCATION (id->block) = input_location; ! prepend_lexical_block (gimple_block (stmt), id->block); ! } /* Local declarations will be replaced by their equivalents in this map. */ *************** expand_call_inline (basic_block bb, gimp *** 3942,3968 **** if (DECL_INITIAL (fn)) { ! tree *var; ! prepend_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id)); ! gcc_checking_assert (BLOCK_SUBBLOCKS (id->block) ! && (BLOCK_CHAIN (BLOCK_SUBBLOCKS (id->block)) ! == NULL_TREE)); ! /* Move vars for PARM_DECLs from DECL_INITIAL block to id->block, ! otherwise for DWARF DW_TAG_formal_parameter will not be children of ! DW_TAG_inlined_subroutine, but of a DW_TAG_lexical_block ! under it. The parameters can be then evaluated in the debugger, ! but don't show in backtraces. */ ! for (var = &BLOCK_VARS (BLOCK_SUBBLOCKS (id->block)); *var; ) ! if (TREE_CODE (DECL_ORIGIN (*var)) == PARM_DECL) ! { ! tree v = *var; ! *var = TREE_CHAIN (v); ! TREE_CHAIN (v) = BLOCK_VARS (id->block); ! BLOCK_VARS (id->block) = v; ! } ! else ! var = &TREE_CHAIN (*var); } /* Return statements in the function body will be replaced by jumps --- 3954,3986 ---- if (DECL_INITIAL (fn)) { ! if (gimple_block (stmt)) ! { ! tree *var; ! prepend_lexical_block (id->block, ! remap_blocks (DECL_INITIAL (fn), id)); ! gcc_checking_assert (BLOCK_SUBBLOCKS (id->block) ! && (BLOCK_CHAIN (BLOCK_SUBBLOCKS (id->block)) ! == NULL_TREE)); ! /* Move vars for PARM_DECLs from DECL_INITIAL block to id->block, ! otherwise for DWARF DW_TAG_formal_parameter will not be children of ! DW_TAG_inlined_subroutine, but of a DW_TAG_lexical_block ! under it. The parameters can be then evaluated in the debugger, ! but don't show in backtraces. */ ! for (var = &BLOCK_VARS (BLOCK_SUBBLOCKS (id->block)); *var; ) ! if (TREE_CODE (DECL_ORIGIN (*var)) == PARM_DECL) ! { ! tree v = *var; ! *var = TREE_CHAIN (v); ! TREE_CHAIN (v) = BLOCK_VARS (id->block); ! BLOCK_VARS (id->block) = v; ! } ! else ! var = &TREE_CHAIN (*var); ! } ! else ! remap_blocks_to_null (DECL_INITIAL (fn), id); } /* Return statements in the function body will be replaced by jumps *************** expand_call_inline (basic_block bb, gimp *** 4106,4112 **** inlined. If we don't do this now, we can lose the information about the variables in the function when the blocks get blown away as soon as we remove the cgraph node. */ ! (*debug_hooks->outlining_inline_function) (cg_edge->callee->symbol.decl); /* Update callgraph if needed. */ cgraph_remove_node (cg_edge->callee); --- 4124,4131 ---- inlined. If we don't do this now, we can lose the information about the variables in the function when the blocks get blown away as soon as we remove the cgraph node. */ ! if (gimple_block (stmt)) ! (*debug_hooks->outlining_inline_function) (cg_edge->callee->symbol.decl); /* Update callgraph if needed. */ cgraph_remove_node (cg_edge->callee);