The following fixes the ICE part of PR78383. We ICE when trying to turn a computed goto to a CFG edge when we know the label but that label is in another function (IPA propagation exposed this knowledge).
The transform shows that we miss a DECL_NONLOCAL on the label because we happily miscompile the testcase by moving the label freely before the call to the lambda. This results in _ZZ4mainENKUlPvE_clES_.isra.0.constprop.1: main: call _ZZ4mainENKUlPvE_clES_.isra.0.constprop.1 where you can see the goto has been optimized somehow on RTL as well. Final GIMPLE is main()::<lambda(void*)> () { <bb 2>: goto &label; } int main() () { label: main()::<lambda(void*)>::_ZZ4mainENKUlPvE_clES_.isra.0.constprop (); } and initial RTL is already broken: ;; goto &label; (insn 5 4 6 (set (reg:DI 87) (label_ref/v:DI 0)) "t.ii":3 -1 (nil)) (jump_insn 6 5 7 (set (pc) (reg:DI 87)) "t.ii":3 -1 (nil)) looks like it might be a bad idea to freely allow LABEL_DECL address propagation but in the end it works fine for DECL_NONLOCAL labels so I think this is what we miss (the label is not marked DECL_NONLOCAL). Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Will commit w/o the testcase (because that is still miscompiled). Richard. 2016-11-17 Richard Biener <rguent...@suse.de> PR middle-end/78383 * tree-cfgcleanup.c (cleanup_control_flow_bb): Do not turn non-local goto into CFG. diff --git a/gcc/testsuite/g++.dg/torture/pr78383.C b/gcc/testsuite/g++.dg/torture/pr78383.C new file mode 100644 index 0000000..2b35bc7 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr78383.C @@ -0,0 +1,11 @@ +// { dg-do run } + +int main() +{ + auto f = [](void* ptr) { goto *ptr; }; + + f(&&label); + +label: + return 0; +} diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index 21873f8..fe22ed3 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -230,6 +230,8 @@ cleanup_control_flow_bb (basic_block bb, bool first_p) edges which do not go to the right block. For the one edge which goes to the right block, fix up its flags. */ label = TREE_OPERAND (gimple_goto_dest (stmt), 0); + if (DECL_CONTEXT (label) != cfun->decl) + return retval; target_block = label_to_block (label); for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) {