Hi! The code in this function assumes that lhs is the lhs of new_stmt (it tests that new_stmt is a noreturn call etc.), but that is only the case if new_stmt == e->call_stmt. But in the function it can be set to various other stmts. Nothing tests the lhs before this noreturn handling, so this patch fixes it by moving the initialization of lhs right before the use.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-12-07 Jakub Jelinek <ja...@redhat.com> PR c++/78692 * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Set lhs var to lhs of new_stmt right before noreturn handling rather than to lhs of e->call_stmt early. * g++.dg/torture/pr78692.C: New test. --- gcc/cgraph.c.jj 2016-11-30 13:57:11.000000000 +0100 +++ gcc/cgraph.c 2016-12-06 09:51:32.513140728 +0100 @@ -1271,7 +1271,6 @@ cgraph_edge::redirect_call_stmt_to_calle cgraph_edge *e = this; tree decl = gimple_call_fndecl (e->call_stmt); - tree lhs = gimple_call_lhs (e->call_stmt); gcall *new_stmt; gimple_stmt_iterator gsi; bool skip_bounds = false; @@ -1526,6 +1525,7 @@ cgraph_edge::redirect_call_stmt_to_calle gimple_call_set_fntype (new_stmt, TREE_TYPE (e->callee->decl)); /* If the call becomes noreturn, remove the LHS if possible. */ + tree lhs = gimple_call_lhs (new_stmt); if (lhs && gimple_call_noreturn_p (new_stmt) && (VOID_TYPE_P (TREE_TYPE (gimple_call_fntype (new_stmt))) --- gcc/testsuite/g++.dg/torture/pr78692.C.jj 2016-12-06 09:55:39.295999164 +0100 +++ gcc/testsuite/g++.dg/torture/pr78692.C 2016-12-06 09:55:25.000000000 +0100 @@ -0,0 +1,26 @@ +// PR c++/78692 + +int a; +void *b; +extern "C" { +struct C { + virtual int d (); +}; +struct E { + virtual int operator () (int, const void *, int) = 0; +}; +class F { + int g (); + int h; + E &i; +}; +struct : C, E { + int operator () (int, const void *, int) { throw int(); } +} j; + +int +F::g () +{ + a = i (h, b, 0); +} +} Jakub