https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71105
Bug ID: 71105 Summary: [6 regression] lambas with default captures improperly have function pointer conversions Product: gcc Version: 6.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: Casey at Carter dot net Target Milestone: --- Created attachment 38483 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=38483&action=edit Minimal test case N4582 [expr.prim.lambda]/7 says: The closure type for a non-generic lambda-expression with no lambda-capture has a conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. ... For a generic lambda with no lambda-capture, the closure type has a conversion function template to pointer to function. The conversion function template has the same invented template-parameter-list, and the pointer to function has the same parameter types, as the function call operator template. ... So all of: static_cast<void(*)()>([]{}); static_cast<void(*)(int)>([](auto){}); static_cast<float(*)(float)>([](auto x){ return x; }); should compile. These should all be ill-formed since the lambdas have lambda-captures: static_cast<void(*)()>([i]{}); static_cast<void(*)()>([=]{}); static_cast<void(*)()>([&]{}); static_cast<void(*)(int)>([i](auto){}); static_cast<void(*)(int)>([=](auto){}); static_cast<void(*)(int)>([&](auto){}); static_cast<float(*)(float)>([i](auto x){ return x; }); static_cast<float(*)(float)>([=](auto x){ return x; }); static_cast<float(*)(float)>([&](auto x){ return x; }); clang (tested 3.4 - 3.9, all versions that implement generic lambdas) diagnoses all of these conversions as ill-formed; gcc (4.9.0 - 6.1.0, again all versions that implement generic lambdas) diagnoses only those with explicit captures. This issue is significant when a library composes function objects via private inheritance to take advantage of the empty base optimization and it adapts a (possibly) underconstrained generic lambda to a different/larger valid space of parameter types. For example, from range-v3: #include <type_traits> template <class F> struct indirected : F { indirected(F f) : F(f) {} template <class I> auto operator()(I i) -> decltype(std::declval<F&>()(*i)) { return static_cast<F&>(*this)(*i); } }; int main() { auto f = [=](auto i) { return i + i; }; auto i = indirected<decltype(f)>{f}; static_assert(std::is_same<decltype(i(std::declval<int*>())), int>(), ""); } This program compiles correctly with the GCC 4.9 and 5 series compilers, 6.1 diagnoses the static_assert line (See http://melpon.org/wandbox/permlink/yy61pk0iJRfUVBya): prog.cc: In instantiation of 'main()::<lambda(auto:1)> [with auto:1 = int*]': prog.cc:13:24: required by substitution of 'template<class auto:1> main()::<lambda(auto:1)>::operator decltype (((main()::<lambda(auto:1)>)0u).operator()(static_cast<auto:1>(<anonymous>))) (*)(auto:1)() const [with auto:1 = int*]' prog.cc:15:63: required from here prog.cc:13:37: error: invalid operands of types 'int*' and 'int*' to binary 'operator+' auto f = [=](auto i) { return i + i; }; ~~^~~