This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/71105] New: [6 regression] lambas with default captures improperly have function pointer conversions


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; };
                                   ~~^~~

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]