Hi! The FRE devirtualization unlike gimple-fold or other places would transform some method call with TREE_ADDRESSABLE lhs into __builtin_unreachable call with the same lhs, which is invalid (__builtin_unreachable returns void). Also, gimple_call_fntype has not been adjusted in these cases.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? What about 6.x? Do you prefer it in 6.2, or 6.3? 2016-08-16 Jakub Jelinek <ja...@redhat.com> PR middle-end/77259 * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): If turning a call into __builtin_unreachable-like noreturn call, adjust gimple_call_set_fntype and remove lhs if needed. * g++.dg/ipa/devirt-52.C: New test. --- gcc/tree-ssa-pre.c.jj 2016-08-12 17:33:46.000000000 +0200 +++ gcc/tree-ssa-pre.c 2016-08-16 11:24:53.605976981 +0200 @@ -4543,6 +4543,32 @@ eliminate_dom_walker::before_dom_childre lang_hooks.decl_printable_name (fn, 2)); } gimple_call_set_fndecl (call_stmt, fn); + /* If changing the call to __builtin_unreachable + or similar noreturn function, adjust gimple_call_fntype + too. */ + if ((gimple_call_flags (call_stmt) & ECF_NORETURN) + && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn))) + && TYPE_ARG_TYPES (TREE_TYPE (fn)) + && (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fn))) + == void_type_node)) + gimple_call_set_fntype (call_stmt, TREE_TYPE (fn)); + tree lhs = gimple_call_lhs (call_stmt); + /* If the call becomes noreturn, remove the lhs. */ + if (lhs + && gimple_call_noreturn_p (call_stmt) + && (VOID_TYPE_P (TREE_TYPE (gimple_call_fntype + (call_stmt))) + || should_remove_lhs_p (lhs))) + { + if (TREE_CODE (lhs) == SSA_NAME) + { + tree var = create_tmp_var (TREE_TYPE (lhs)); + tree def = get_or_create_ssa_default_def (cfun, var); + gimple *new_stmt = gimple_build_assign (lhs, def); + gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); + } + gimple_call_set_lhs (call_stmt, NULL_TREE); + } maybe_remove_unused_call_args (cfun, call_stmt); gimple_set_modified (stmt, true); } --- gcc/testsuite/g++.dg/ipa/devirt-52.C.jj 2016-08-16 11:08:49.943108247 +0200 +++ gcc/testsuite/g++.dg/ipa/devirt-52.C 2016-08-16 11:32:25.295300721 +0200 @@ -0,0 +1,56 @@ +// PR middle-end/77259 +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } + +template <typename, typename = int> class A; +template <typename, typename> struct A +{ + A (A &&); +}; +template <typename S, typename T, typename U> +A<S> operator+(S *, const A<T, U> &); +template <typename S, typename T, typename U> +void operator+(const A<T, U> &, S *); +struct B +{ + template <typename V> B (V); +}; +template <typename V> V foo (B) {} +class C; +template <typename> struct D +{ + C *operator->() { return d; } + C *d; +}; +struct C +{ + virtual A<int> bar (); +}; +struct E +{ + ~E (); + virtual A<char> bar (const B &) const; +}; +template <typename> struct F : E +{ +}; +template <typename W> struct F<D<W>> : E +{ + A<char> bar (const B &) const try + { + D<W> a = baz (); + } + catch (int) + { + } + D<W> baz () const + { + D<C> b = foo<D<C>>(0); + "" + b->bar () + ""; + } +}; +struct G : F<D<int>> +{ + G (int); +}; +void test () { G (0); } Jakub