diff mbox series

C++ PATCH to implement C++20 P0806R2, Deprecate implicit capture of this via [=]

Message ID 20180812035319.GN4317@redhat.com
State New
Headers show
Series C++ PATCH to implement C++20 P0806R2, Deprecate implicit capture of this via [=] | expand

Commit Message

Marek Polacek Aug. 12, 2018, 3:53 a.m. UTC
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  <polacek@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.

Comments

Jason Merrill Aug. 13, 2018, 6:27 a.m. UTC | #1
On Sun, Aug 12, 2018 at 3:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> -      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);

This reformatting seems unnecessary, and I prefer to avoid unnecessary
reformatting to avoid noise in 'git blame'. The rest of the patch is
OK.

Jason
Marek Polacek Aug. 13, 2018, 3:55 p.m. UTC | #2
On Mon, Aug 13, 2018 at 06:27:53PM +1200, Jason Merrill wrote:
> On Sun, Aug 12, 2018 at 3:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> > -      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);
> 
> This reformatting seems unnecessary, and I prefer to avoid unnecessary
> reformatting to avoid noise in 'git blame'. The rest of the patch is
> OK.

Thanks, this is what I committed.

2018-08-13  Marek Polacek  <polacek@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))
     {
@@ -720,6 +716,19 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
 				 == 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; };
+      };
+    };
+  }
+};
diff mbox series

Patch

--- 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; };
+      };
+    };
+  }
+};