version: g++ (Compiler-Explorer-Build) 10.2.0 arguments: -O2 -std=c++17 -pedantic-errors ``` struct A { A() = default; A(const A&) {} }; void (*fptr)(A) = [](auto){}; ``` <source>: In static member function 'static constexpr decltype (((const<lambda(auto:1)>*)0)->operator()<auto:1>(static_cast<auto:1&&>(<anonymous>)))<lambda(auto:1)>::_FUN(auto:1) [with auto:1 = A]': <source>:6:28: internal compiler error: in create_tmp_var, at gimple-expr.c:482 6 | void (*fptr)(A) = [](auto){}; | ^ The ICE seems to happen when the by-value parameter's type is not trivially copyable. It can also be reproduced with a non-trivial destructor. If the copy-constructor is deleted then it fails to compile with a non-ice error. Related: PR 86943 In my understanding gcc tries to copy/move the by-value parameter in the free function to pass it to `closure{}(args)`. I don't think that copying/moving the by-value argument is correct. The effect of calling the resulting function pointer should be equivalent to calling the operator() on the closure object, it's not expressed in terms of forwarding the parameters: https://timsong-cpp.github.io/cppwp/n4659/expr.prim.lambda.closure#8 It's more precisely spelled out in C++20, as there it can be expressed it in terms of a default constructed object of the closure type: http://eel.is/c++draft/expr.prim.lambda.closure#10.sentence-1
Confirmed, started with r10-599-gc652ff8312433483.
So, shouldn't either the cp/call.c change have been: - && ! TREE_ADDRESSABLE (TREE_TYPE (arg))) + && ! TREE_ADDRESSABLE (TREE_TYPE (arg)) + && simple_empty_class_p (TREE_TYPE (arg), arg, INIT_EXPR)) rather than - && ! TREE_ADDRESSABLE (TREE_TYPE (arg))) + && simple_empty_class_p (TREE_TYPE (arg), arg, INIT_EXPR)) so it would don't try to handle TREE_ADDRESSABLE classes this way? Or perhaps simple_empty_class_p should punt for TREE_ADDRESSABLE types? In any case, passing CONSTRUCTOR with TREE_ADDRESSABLE type directly as argument to function call leads to creating temporaries of the type, which aren't allowed.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:bdbca69e0720fa9062fe71782235141f629ae006 commit r11-7142-gbdbca69e0720fa9062fe71782235141f629ae006 Author: Jason Merrill <jason@redhat.com> Date: Mon Feb 8 17:04:03 2021 -0500 c++: generic lambda, fn* conv, empty class [PR98326] Here, in the thunk returned from the captureless lambda conversion to pointer-to-function, we try to pass through invisible reference parameters by reference, without doing a copy. The empty class copy optimization was messing that up. gcc/cp/ChangeLog: PR c++/98326 PR c++/20408 * cp-gimplify.c (simple_empty_class_p): Don't touch an invisiref parm. gcc/testsuite/ChangeLog: PR c++/98326 * g++.dg/cpp1y/lambda-generic-empty1.C: New test.
The releases/gcc-10 branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:031e97207463710797625382baff112b6c3ade51 commit r10-9362-g031e97207463710797625382baff112b6c3ade51 Author: Jason Merrill <jason@redhat.com> Date: Mon Feb 8 17:04:03 2021 -0500 c++: generic lambda, fn* conv, empty class [PR98326] Here, in the thunk returned from the captureless lambda conversion to pointer-to-function, we try to pass through invisible reference parameters by reference, without doing a copy. The empty class copy optimization was messing that up. gcc/cp/ChangeLog: PR c++/98326 PR c++/20408 * cp-gimplify.c (simple_empty_class_p): Don't touch an invisiref parm. gcc/testsuite/ChangeLog: PR c++/98326 * g++.dg/cpp1y/lambda-generic-empty1.C: New test.
Fixed for 10.3/11.