Hi! On the following testcase, the call to operator () is marked as CALL_FROM_THUNK_P and therefore genericization ignores all subtrees thereof. Unfortunately, one of the arguments is a move ctor call which is not itself CALL_FROM_THUNK_P and thus we need to genericize its arguments, otherwise we pass address of a temporary which holds a reference value instead of the reference itself.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Or should CALL_FROM_THUNK_P not be set in this call (it is set in maybe_add_lambda_conv_op and then copied over during tsubst*). Furthermore, clang++ apparently doesn't call the move ctor + dtor at all and uses just the originally constructed var. Is what GCC does right, or clang? 2018-11-23 Jakub Jelinek <ja...@redhat.com> PR c++/86943 * cp-gimplify.c (cp_genericize_r): For CALL_FROM_THUNK_P CALL_EXPRs don't walk just DECL_P arguments, do walk more complex arguments. * g++.dg/cpp1y/pr86943.C: New test. --- gcc/cp/cp-gimplify.c.jj 2018-11-17 00:16:41.924381941 +0100 +++ gcc/cp/cp-gimplify.c 2018-11-23 17:29:24.764459373 +0100 @@ -1108,6 +1108,18 @@ cp_genericize_r (tree *stmt_p, int *walk || (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt))) { *walk_subtrees = 0; + /* For CALL_EXPRs, if the arguments aren't decls, recurse into them + though. See PR86943. */ + if (TREE_CODE (stmt) == CALL_EXPR) + { + unsigned int n = call_expr_nargs (stmt); + for (unsigned int i = 0; i < n; i++) + { + tree &arg = CALL_EXPR_ARG (stmt, i); + if (!DECL_P (arg)) + cp_walk_tree (&arg, cp_genericize_r, data, NULL); + } + } return NULL; } --- gcc/testsuite/g++.dg/cpp1y/pr86943.C.jj 2018-11-23 18:04:08.260852111 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr86943.C 2018-11-23 18:03:45.798224687 +0100 @@ -0,0 +1,32 @@ +// PR c++/86943 +// { dg-do run { target c++14 } } + +int c[3]; + +struct S +{ + S () : s (1234) { c[0]++; } + S (const S &) { __builtin_abort (); } + S (S &&x) noexcept { if (x.s != 1234) __builtin_abort (); s = 1234; x.s = 2345; c[1]++; } + ~S () { if (s != 1234 && s != 2345) __builtin_abort (); c[2]++; } + int s; +}; + +using F = void (*) (S); + +F +foo () +{ + return [] (auto val) { if (val.s != 1234) __builtin_abort (); }; +} + +int +main () +{ + { + volatile F f = foo (); + f ({}); + } + if (c[0] + c[1] != c[2]) + __builtin_abort (); +} Jakub