The following patch avoids streaming extern var and function decls into the global decls and types section when streaming a tree chain list (effectively only when processing BLOCK_VARS). This avoids the last LTO debug-info ICE I know of (knocks on wood) and provides a cleaner (well ...) fix for PR48437 as well.
LTO bootstrapped on x86_64-unknown-linux-gnu, testing in progress, so is SPEC 2k6 build with -g (hopefully now without ICEs as well). I plan to commit this tomorrow if all goes well and declare LTO debug-info perfect for 4.7. Richard. 2011-12-14 Richard Guenther <rguent...@suse.de> Revert PR lto/48437 * lto-streamer-out.c (tree_is_indexable): Exclude block-local extern declarations. PR lto/48508 PR lto/48437 * tree-streamer-out.c (streamer_write_chain): Stream DECL_EXTERNAL VAR_DECLs and FUNCTION_DECLs locally. * g++.dg/lto/pr48508-1_0.C: New testcase. * g++.dg/lto/pr48508-1_1.C: Likewise. Index: gcc/lto-streamer-out.c =================================================================== *** gcc/lto-streamer-out.c (revision 182335) --- gcc/lto-streamer-out.c (working copy) *************** tree_is_indexable (tree t) *** 129,144 **** else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t) && !TREE_STATIC (t)) return false; - /* If this is a decl generated for block local externs for - debug info generation, stream it unshared alongside BLOCK_VARS. */ - else if (VAR_OR_FUNCTION_DECL_P (t) - /* ??? The following tests are a literal match on what - c-decl.c:pop_scope does. */ - && TREE_PUBLIC (t) - && DECL_EXTERNAL (t) - && DECL_CONTEXT (t) - && TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL) - return false; /* Variably modified types need to be streamed alongside function bodies because they can refer to local entities. Together with them we have to localize their members as well. --- 129,134 ---- Index: gcc/tree-streamer-out.c =================================================================== *** gcc/tree-streamer-out.c (revision 182335) --- gcc/tree-streamer-out.c (working copy) *************** streamer_write_chain (struct output_bloc *** 405,411 **** saved_chain = TREE_CHAIN (t); TREE_CHAIN (t) = NULL_TREE; ! stream_write_tree (ob, t, ref_p); TREE_CHAIN (t) = saved_chain; t = TREE_CHAIN (t); --- 405,417 ---- saved_chain = TREE_CHAIN (t); TREE_CHAIN (t) = NULL_TREE; ! /* We avoid outputting external vars or functions by reference ! to the global decls section as we do not want to have them ! enter decl merging. This is, of course, only for the call ! for streaming BLOCK_VARS, but other callers are safe. */ ! stream_write_tree (ob, t, ! ref_p && !(VAR_OR_FUNCTION_DECL_P (t) ! && DECL_EXTERNAL (t))); TREE_CHAIN (t) = saved_chain; t = TREE_CHAIN (t); Index: gcc/testsuite/g++.dg/lto/pr48508-1_0.C =================================================================== *** gcc/testsuite/g++.dg/lto/pr48508-1_0.C (revision 0) --- gcc/testsuite/g++.dg/lto/pr48508-1_0.C (revision 0) *************** *** 0 **** --- 1,7 ---- + // { dg-lto-do link } + // { dg-lto-options { { -g -O2 -flto -flto-partition=none } } } + + void __attribute__((externally_visible)) + foo (int i) + { + } Index: gcc/testsuite/g++.dg/lto/pr48508-1_1.C =================================================================== *** gcc/testsuite/g++.dg/lto/pr48508-1_1.C (revision 0) --- gcc/testsuite/g++.dg/lto/pr48508-1_1.C (revision 0) *************** *** 0 **** --- 1,10 ---- + static void + bar (void) + { + extern void foo (int); + foo (0); + } + int main() + { + bar (); + }