https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636
Adam Butcher <abutcher at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Assignee|abutcher at gcc dot gnu.org |unassigned at gcc dot gnu.org --- Comment #22 from Adam Butcher <abutcher at gcc dot gnu.org> --- Firstly, apologies for not unassigning myself from this; I hope it hasn't stopped others from looking into it. I had meant to unassign myself after my last attempt to fix this in early 2015. Since then I haven't had any spare time to look into it. The patch I submitted in 2015 (https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00617.html) does indeed solve this. However, it captures 'this' in generic lambdas in some cases where it is not required. This is not ideal (see the follow up list discussion starting from Jason's review https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00934.html). The current implementation, though non-optimal, may be preferable to waiting for a better version as at least code can be written which is correct, minimal and doesn't surprise users (i.e. no 'this->' workarounds required). This bug could be closed in favor of a "'this' is captured in generic lambdas when it is not necessary'" with proofs along the lines as I suggested in https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00959.html and https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00973.html. I've just done some 'this' capture analysis using Clang (3.9.0), the current stock ArchLinux GCC (6.2.1 20160830) and my own build of GCC (7.0.0 20161215) including the patches above. Clang stops short of a fully optimal solution. In fact it is less optimal than GCC even for monomorphic lambdas. It seems to capture 'this' whenever it sees a name within the lambda body that resolves to a member, whether or not that reference requires 'this'. It even captures 'this' when a reference is made to static member of a _different_ class which is surprising. The following show a handful of cases. The comments inline indicate whether 'this' is captured (sizeof lambda == 8) or not captured (sizeof lambda == 1) for Clang (C), GCC (G) and GCC with my 2015 patches (G'). The line tagged with the asterisk is the only case in this set where the patch is non-optimal; "f (2.4)" unambiguously resolves to the static member "A::f", so 'this' need not be captured. Since, with the patch, GCC is correct and more optimal than Clang, I think it would make sense to go with it and raise a separate ticket to address the other issue. struct A { void b (); void f (int); static void f (double); }; struct O { void x (int); static void x (double); }; namespace N { void y (double); } template <int> struct diag; void A::b() { auto l0 = [&](auto z) { f (z); }; diag<sizeof l0> {}; // C:8 G:1 G':8 auto l1 = [&](auto) { f (2.4); }; diag<sizeof l1> {}; // C:8 G:1 G':8 * auto l2 = [&](auto) { O::x (2.4); }; diag<sizeof l2> {}; // C:8 G:1 G':1 auto l3 = [&](auto) { N::y (2.4); }; diag<sizeof l3> {}; // C:1 G:1 G':1 auto l4 = [&](auto) { }; diag<sizeof l4> {}; // C:1 G:1 G':1 auto l5 = [&](int z) { f (z); }; diag<sizeof l5> {}; // C:8 G:8 G':8 auto l6 = [&](int) { f (2.4); }; diag<sizeof l6> {}; // C:8 G:1 G':1 auto l7 = [&](int) { O::x (2.4); }; diag<sizeof l7> {}; // C:8 G:1 G':1 auto l8 = [&](int) { N::y (2.4); }; diag<sizeof l8> {}; // C:1 G:1 G':1 auto l9 = [&](int) { }; diag<sizeof l9> {}; // C:1 G:1 G':1 }