C++ PATCH for c++/66999 - 'this' captured by reference

Message ID 20190609005136.GY5989@redhat.com
State New
Headers show
Series
  • C++ PATCH for c++/66999 - 'this' captured by reference
Related show

Commit Message

Marek Polacek June 9, 2019, 12:51 a.m.
This patch improves a diagnostic when parsing a lambda introducer; in particular,
we should handle '&this' better than we currently do.  clang/icc specifically
point out that 'this' cannot be captured by reference, let's do the same.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-06-08  Marek Polacek  <polacek@redhat.com>

	PR c++/66999 - 'this' captured by reference.
	* parser.c (cp_parser_lambda_introducer): Reject `&this'.  Use
	cp_lexer_nth_token_is instead of cp_lexer_peek_nth_token.

	* g++.dg/cpp0x/lambda/lambda-this21.C: New test.

Comments

Jason Merrill June 12, 2019, 8:16 p.m. | #1
On 6/8/19 8:51 PM, Marek Polacek wrote:
> This patch improves a diagnostic when parsing a lambda introducer; in particular,

> we should handle '&this' better than we currently do.  clang/icc specifically

> point out that 'this' cannot be captured by reference, let's do the same.

> 

> Bootstrapped/regtested on x86_64-linux, ok for trunk?


OK.

Jason

Patch

diff --git gcc/cp/parser.c gcc/cp/parser.c
index 308b2d4ad70..74796e197fe 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -10526,7 +10526,8 @@  cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 
   /* Record default capture mode.  "[&" "[=" "[&," "[=,"  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_AND)
-      && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_NAME)
+      && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)
+      && !cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_THIS))
     LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_REFERENCE;
   else if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
     LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_COPY;
@@ -10609,6 +10610,17 @@  cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 	  continue;
 	}
 
+      /* But reject `&this'.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_AND)
+	  && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_THIS))
+	{
+	  error_at (cp_lexer_peek_token (parser->lexer)->location,
+		    "%<this%> cannot be captured by reference");
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_lexer_consume_token (parser->lexer);
+	  continue;
+	}
+
       bool init_pack_expansion = false;
       location_t ellipsis_loc = UNKNOWN_LOCATION;
       if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
diff --git gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this21.C gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this21.C
new file mode 100644
index 00000000000..a3256b5700f
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this21.C
@@ -0,0 +1,10 @@ 
+// PR c++/66999 - 'this' captured by reference.
+// { dg-do compile { target c++11 } }
+
+struct X {
+  void bar (int n)
+    {
+      auto l1 = [&this] { }; // { dg-error ".this. cannot be captured by reference" }
+      auto l2 = [=, &this] { }; // { dg-error ".this. cannot be captured by reference" }
+    }
+};