https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86943
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org, | |nathan at gcc dot gnu.org --- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> --- extern "C" int printf (const char *fmt, ...); struct S { S () { printf ("default-construct %p\n", this); } S (const S &x) { printf ("copy-construct %p from %p\n", this, &x); } S (S &&x) noexcept { printf ("move-construct %p from %p\n", this, &x); } ~S () { printf ("destroy %p\n", this); } }; using F = void (*) (S); F foo () { return [] (auto val) { printf ("called %p\n", &val); }; } int main () { volatile F cb = foo (); cb ({}); return 0; } The extra indirection is because in _FUN we have: <<cleanup_point <<< Unknown tree: expr_stmt foo()::<lambda(auto:1)>::operator()<S> (0B, &TARGET_EXPR <D.2164, <<< Unknown tree: aggr_init_expr 5 __ct_comp D.2164 (struct S *) <<< Unknown tree: void_cst >>> (struct S &) &D.2160 >>>>) >>>>>; return; and CALL_FROM_THUNK_P is set on the operator() call. cp_genericize on _FUN changes the D.2160 argument, originally with type S, is changed to S & and the PARM_DECL turned into DECL_BY_REFERENCE one, but because the call is CALL_FROM_THUNK_P, no adjustment of the arguments is done: /* Don't dereference parms in a thunk, pass the references through. */ if ((TREE_CODE (stmt) == CALL_EXPR && CALL_FROM_THUNK_P (stmt)) || (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt))) { *walk_subtrees = 0; return NULL; } Do we want to just prevent changing the direct PARM_DECL arguments of such calls, but still recurse into more complex arguments? Or is it incorrect that CALL_FROM_THUNK_P is set here?