When we capture the current object (*this) implicitly, it is always captured by reference, even if the capture default is =. This is surprising and irregular so this proposal <http://wg21.link/p0806r2> deprecates implicit capture of this via [=] (not via [&]). Users should now use [=, this] (same as [=], added by P0409R2), or [=, *this].
This patch adds a -Wdeprecated warning to address it. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2018-08-11 Marek Polacek <pola...@redhat.com> P0806R2 - Deprecate implicit capture of this via [=] * lambda.c (add_default_capture): Formatting fixes. Warn about deprecated implicit capture of this via [=]. * g++.dg/cpp2a/lambda-this1.C: New test. * g++.dg/cpp2a/lambda-this2.C: New test. * g++.dg/cpp2a/lambda-this3.C: New test. --- gcc/cp/lambda.c +++ gcc/cp/lambda.c @@ -695,14 +695,10 @@ tree add_default_capture (tree lambda_stack, tree id, tree initializer) { bool this_capture_p = (id == this_identifier); - tree var = NULL_TREE; - tree saved_class_type = current_class_type; - tree node; - - for (node = lambda_stack; + for (tree node = lambda_stack; node; node = TREE_CHAIN (node)) { @@ -711,15 +707,26 @@ add_default_capture (tree lambda_stack, tree id, tree initializer) current_class_type = LAMBDA_EXPR_CLOSURE (lambda); if (DECL_PACK_P (initializer)) initializer = make_pack_expansion (initializer); - var = add_capture (lambda, - id, - initializer, - /*by_reference_p=*/ - (this_capture_p - || (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) - == CPLD_REFERENCE)), - /*explicit_init_p=*/false); + var = add_capture (lambda, id, initializer, + /*by_reference_p=*/ + (this_capture_p + || (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) + == CPLD_REFERENCE)), + /*explicit_init_p=*/false); initializer = convert_from_reference (var); + + /* Warn about deprecated implicit capture of this via [=]. */ + if (cxx_dialect >= cxx2a + && this_capture_p + && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_COPY + && !in_system_header_at (LAMBDA_EXPR_LOCATION (lambda))) + { + if (warning_at (LAMBDA_EXPR_LOCATION (lambda), OPT_Wdeprecated, + "implicit capture of %qE via %<[=]%> is deprecated " + "in C++20", this_identifier)) + inform (LAMBDA_EXPR_LOCATION (lambda), "add explicit %<this%> or " + "%<*this%> capture"); + } } current_class_type = saved_class_type; --- gcc/testsuite/g++.dg/cpp2a/lambda-this1.C +++ gcc/testsuite/g++.dg/cpp2a/lambda-this1.C @@ -0,0 +1,51 @@ +// P0806R2 +// { dg-do compile } +// { dg-options "-std=c++2a" } + +struct X { + int x; + void foo (int n) { + auto a1 = [=] { x = n; }; // { dg-warning "implicit capture" } + auto a2 = [=, this] { x = n; }; + auto a3 = [=, *this]() mutable { x = n; }; + auto a4 = [&] { x = n; }; + auto a5 = [&, this] { x = n; }; + auto a6 = [&, *this]() mutable { x = n; }; + + auto a7 = [=] { // { dg-warning "implicit capture" } + auto a = [=] { // { dg-warning "implicit capture" } + auto a2 = [=] { x = n; }; // { dg-warning "implicit capture" } + }; + }; + + auto a8 = [=, this] { + auto a = [=, this] { + auto a2 = [=, this] { x = n; }; + }; + }; + + auto a9 = [=, *this]() mutable { + auto a = [=, *this]() mutable { + auto a2 = [=, *this]() mutable { x = n; }; + }; + }; + + auto a10 = [&] { + auto a = [&] { + auto a2 = [&] { x = n; }; + }; + }; + + auto a11 = [&, this] { + auto a = [&, this] { + auto a2 = [&, this] { x = n; }; + }; + }; + + auto a12 = [&, *this]() mutable { + auto a = [&, *this]() mutable { + auto a2 = [&, *this]() mutable { x = n; }; + }; + }; + } +}; --- gcc/testsuite/g++.dg/cpp2a/lambda-this2.C +++ gcc/testsuite/g++.dg/cpp2a/lambda-this2.C @@ -0,0 +1,51 @@ +// P0806R2 +// { dg-do compile } +// { dg-options "-std=c++2a -Wno-deprecated" } + +struct X { + int x; + void foo (int n) { + auto a1 = [=] { x = n; }; // { dg-bogus "implicit capture" } + auto a2 = [=, this] { x = n; }; + auto a3 = [=, *this]() mutable { x = n; }; + auto a4 = [&] { x = n; }; + auto a5 = [&, this] { x = n; }; + auto a6 = [&, *this]() mutable { x = n; }; + + auto a7 = [=] { // { dg-bogus "implicit capture" } + auto a = [=] { // { dg-bogus "implicit capture" } + auto a2 = [=] { x = n; }; // { dg-bogus "implicit capture" } + }; + }; + + auto a8 = [=, this] { + auto a = [=, this] { + auto a2 = [=, this] { x = n; }; + }; + }; + + auto a9 = [=, *this]() mutable { + auto a = [=, *this]() mutable { + auto a2 = [=, *this]() mutable { x = n; }; + }; + }; + + auto a10 = [&] { + auto a = [&] { + auto a2 = [&] { x = n; }; + }; + }; + + auto a11 = [&, this] { + auto a = [&, this] { + auto a2 = [&, this] { x = n; }; + }; + }; + + auto a12 = [&, *this]() mutable { + auto a = [&, *this]() mutable { + auto a2 = [&, *this]() mutable { x = n; }; + }; + }; + } +}; --- gcc/testsuite/g++.dg/cpp2a/lambda-this3.C +++ gcc/testsuite/g++.dg/cpp2a/lambda-this3.C @@ -0,0 +1,55 @@ +// P0806R2 +// { dg-do compile } +// { dg-options "-std=c++17" } + +struct X { + int x; + void foo (int n) { + auto a1 = [=] { x = n; }; // { dg-bogus "implicit capture" } + auto a2 = [=, this] { x = n; }; + // { dg-warning "explicit by-copy capture" "" { target c++17_down } .-1 } + auto a3 = [=, *this]() mutable { x = n; }; + auto a4 = [&] { x = n; }; + auto a5 = [&, this] { x = n; }; + auto a6 = [&, *this]() mutable { x = n; }; + + auto a7 = [=] { // { dg-bogus "implicit capture" } + auto a = [=] { // { dg-bogus "implicit capture" } + auto a2 = [=] { x = n; }; // { dg-bogus "implicit capture" } + }; + }; + + auto a8 = [=, this] { + // { dg-warning "explicit by-copy capture" "" { target c++17_down } .-1 } + auto a = [=, this] { + // { dg-warning "explicit by-copy capture" "" { target c++17_down } .-1 } + auto a2 = [=, this] { x = n; }; + // { dg-warning "explicit by-copy capture" "" { target c++17_down } .-1 } + }; + }; + + auto a9 = [=, *this]() mutable { + auto a = [=, *this]() mutable { + auto a2 = [=, *this]() mutable { x = n; }; + }; + }; + + auto a10 = [&] { + auto a = [&] { + auto a2 = [&] { x = n; }; + }; + }; + + auto a11 = [&, this] { + auto a = [&, this] { + auto a2 = [&, this] { x = n; }; + }; + }; + + auto a12 = [&, *this]() mutable { + auto a = [&, *this]() mutable { + auto a2 = [&, *this]() mutable { x = n; }; + }; + }; + } +};