c++: Fix C++20 variadic lambda init-capture grammar.
authorJason Merrill <jason@redhat.com>
Mon, 24 Feb 2020 01:52:41 +0000 (20:52 -0500)
committerJason Merrill <jason@redhat.com>
Mon, 24 Feb 2020 13:58:31 +0000 (08:58 -0500)
The grammar for variadic init-capture was fixed at the Prague C++ meeting
where we finalized C++20.

gcc/cp/ChangeLog
2020-02-24  Jason Merrill  <jason@redhat.com>

P0780R2: Resolve lambda init-capture pack grammar.
* parser.c (cp_parser_lambda_introducer): Expect &...x=y rather than
...&x=y.

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp2a/lambda-pack-init4.C [new file with mode: 0644]

index 8a3c9f77ad0df2cf2b77b3444afea7af5030159d..cc0f42dfda5b97e2c1fc5fbf0c1a5a37fc00e8a4 100644 (file)
@@ -1,3 +1,9 @@
+2020-02-24  Jason Merrill  <jason@redhat.com>
+
+       P0780R2: Resolve lambda init-capture pack grammar.
+       * parser.c (cp_parser_lambda_introducer): Expect &...x=y rather than
+       ...&x=y.
+
 2020-02-22  Marek Polacek  <polacek@redhat.com>
 
        PR c++/93882
index ee534b5db213244dda5afbe1d65504a795833f1e..87ed2a3a6482ba3c28de077c67598d800a286bad 100644 (file)
@@ -10620,6 +10620,7 @@ 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_nth_token_is (parser->lexer, 2, CPP_ELLIPSIS)
       && !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;
@@ -10715,6 +10716,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
          continue;
        }
 
+      /* Remember whether we want to capture as a reference or not.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_AND))
+       {
+         capture_kind = BY_REFERENCE;
+         cp_lexer_consume_token (parser->lexer);
+       }
+
       bool init_pack_expansion = false;
       location_t ellipsis_loc = UNKNOWN_LOCATION;
       if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
@@ -10727,9 +10735,12 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
          init_pack_expansion = true;
        }
 
-      /* Remember whether we want to capture as a reference or not.  */
-      if (cp_lexer_next_token_is (parser->lexer, CPP_AND))
+      /* Early C++20 drafts had ...& instead of &...; be forgiving.  */
+      if (init_pack_expansion && capture_kind != BY_REFERENCE
+         && cp_lexer_next_token_is (parser->lexer, CPP_AND))
        {
+         pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+                  0, "%<&%> should come before %<...%>");
          capture_kind = BY_REFERENCE;
          cp_lexer_consume_token (parser->lexer);
        }
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init4.C b/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init4.C
new file mode 100644 (file)
index 0000000..e7c815b
--- /dev/null
@@ -0,0 +1,10 @@
+// P2095R0
+// { dg-do compile { target c++2a } }
+// { dg-options "" }
+
+template <class... T>
+void f(T... t)
+{
+  [&...x=t]{};
+  [...&x=t]{};                 // { dg-warning "7:&" }
+}