https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94376
Bug ID: 94376 Summary: When nested inside a lambda body, [=] captures by const value instead of by value Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- David Blaikie, Richard Smith, and I discovered this GCC bug while tracking down a separate bug in llvm::function_ref whose constructor template was improperly SFINAEd so that construction from `const T&&` was done wrong. A GCC bug caused construction from `const T&&` to happen on GCC but not on Clang or EDG. Here's the reduced test case: // https://godbolt.org/z/oCvLpv #include <stdio.h> #include <utility> struct I { I() { puts(__PRETTY_FUNCTION__); } I(I&) { puts(__PRETTY_FUNCTION__); } I(const I&) { puts(__PRETTY_FUNCTION__); } I(I&&) { puts(__PRETTY_FUNCTION__); } I(const I&&) { puts(__PRETTY_FUNCTION__); } void operator++() const {} }; int main() { I i; auto one = [=]() { return [=]() { ++i; }; }(); puts("-----"); auto two = std::move(one); // !! } On the line marked "!!", one's implicitly generated move-constructor calls `I(const I&&)` rather than `I(I&&)` to move the captured copy of `i`. It does this because it has improperly decided that the type of the captured copy of `i` should be `const I` instead of plain old `I`. Richard Smith writes: > [expr.prim.lambda.capture]p10 is the relevant rule: > "The type of such a data member is the referenced type > if the entity is a reference to an object, an lvalue reference > to the referenced function type if the entity is a reference to a function, > or the type of the corresponding captured entity otherwise." > > Regardless of whether you think the captured entity is > the original variable or the member of the outer closure type, > the type of that entity is not const-qualified. > So the inner capture should not have a const-qualified type. Besides exposing bugs in llvm::function_ref (a good effect!), GCC's implementation divergence here could have the bad effect of causing additional expensive copies when lambdas with improperly const-qualified captures are moved around. Example: https://godbolt.org/z/LWEF47 Bug 86697 might be related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86697