On Wed, Mar 13, 2019 at 02:15:25PM -0400, Jason Merrill wrote:
> On 3/12/19 5:42 PM, Marek Polacek wrote:
> > On Tue, Mar 12, 2019 at 04:07:56PM -0400, Jason Merrill wrote:
> > > On 3/12/19 3:59 PM, Marek Polacek wrote:
> > > > As Barry explained in the PR, lambda capture is one of
> > > > 
> > > >     simple-capture ...[opt]
> > > >     ...[opt] init-capture
> > > > 
> > > > where init-capture requires an initializer.  Here we have
> > > > 
> > > >     [...xs...]
> > > > 
> > > > which is ill-formed as it's mingling both of these.
> > > > 
> > > > Bootstrapped/regtested on x86_64-linux, ok for trunk?  Or should I 
> > > > defer to GCC
> > > > 10?
> > > > 
> > > > 2019-03-12  Marek Polacek  <pola...@redhat.com>
> > > > 
> > > >         PR c++/89686 - mixing init-capture and simple-capture in lambda.
> > > >         * parser.c (cp_parser_lambda_introducer): Give error when 
> > > > combining
> > > >         init-capture and simple-capture.
> > > > 
> > > >         * g++.dg/cpp2a/lambda-pack-init2.C: New test.
> > > > 
> > > > diff --git gcc/cp/parser.c gcc/cp/parser.c
> > > > index f95111169ed..d5d8f364752 100644
> > > > --- gcc/cp/parser.c
> > > > +++ gcc/cp/parser.c
> > > > @@ -10721,6 +10721,15 @@ cp_parser_lambda_introducer (cp_parser* 
> > > > parser, tree lambda_expr)
> > > >             {
> > > >               cp_lexer_consume_token (parser->lexer);
> > > >               capture_init_expr = make_pack_expansion 
> > > > (capture_init_expr);
> > > > +             if (init_pack_expansion)
> > > > +               {
> > > > +                 /* We'd already seen '...' so we were expecting an
> > > > +                    init-capture.  But we just saw another '...' which
> > > > +                    would imply a simple-capture.  */
> > > > +                 error_at (capture_token->location,
> > > > +                           "combining init-capture and 
> > > > simple-capture");
> > > 
> > > That diagnostic seems a bit obscure, how about something like "too many
> > > %<...%> in lambda capture"?
> > 
> > Yup, sounds better.
> > 
> > > Or perhaps check to see if there's an initializer after the ..., and
> > > complain about the second ... if so, or the first ... if not.
> > 
> > I tried but we already give diagnostic for [...xs=xs...] or [...xs=...xs]
> > and similar.
> 
> I was thinking about '...xs...=xs'.

Ah, I see.

> > But let's at least use a proper location for the '...'.
> 
> This patch uses the location of ... after the identifier, but if there's no
> initializer, the ... before the identifier is the one we want to flag as
> invalid.

How about this, then?

Bootstrap/regtest running on x86_64-linux, ok for trunk?

2019-03-13  Marek Polacek  <pola...@redhat.com>

        PR c++/89686 - mixing init-capture and simple-capture in lambda.
        * parser.c (cp_parser_lambda_introducer): Give error when combining
        init-capture and simple-capture.

        * g++.dg/cpp2a/lambda-pack-init2.C: New test.

diff --git gcc/cp/parser.c gcc/cp/parser.c
index 8244366e669..14da1a14501 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -10609,12 +10609,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree 
lambda_expr)
        }
 
       bool init_pack_expansion = false;
+      location_t ellipsis_loc = UNKNOWN_LOCATION;
       if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
        {
-         location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+         ellipsis_loc = cp_lexer_peek_token (parser->lexer)->location;
          if (cxx_dialect < cxx2a)
-           pedwarn (loc, 0, "pack init-capture only available with "
-                            "%<-std=c++2a%> or %<-std=gnu++2a%>");
+           pedwarn (ellipsis_loc, 0, "pack init-capture only available with "
+                    "%<-std=c++2a%> or %<-std=gnu++2a%>");
          cp_lexer_consume_token (parser->lexer);
          init_pack_expansion = true;
        }
@@ -10719,8 +10720,21 @@ cp_parser_lambda_introducer (cp_parser* parser, tree 
lambda_expr)
 
          if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
            {
+             location_t loc = cp_lexer_peek_token (parser->lexer)->location;
              cp_lexer_consume_token (parser->lexer);
              capture_init_expr = make_pack_expansion (capture_init_expr);
+             if (init_pack_expansion)
+               {
+                 /* If what follows is an initializer, the second '...' is
+                    invalid.  But for cases like [...xs...], the first one
+                    is invalid.  */
+                 if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)
+                     || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
+                     || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+                   ellipsis_loc = loc;
+                 error_at (ellipsis_loc, "too many %<...%> in lambda capture");
+                 continue;
+               }
            }
        }
 
diff --git gcc/testsuite/g++.dg/cpp2a/lambda-pack-init2.C 
gcc/testsuite/g++.dg/cpp2a/lambda-pack-init2.C
new file mode 100644
index 00000000000..55d689dbc67
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/lambda-pack-init2.C
@@ -0,0 +1,22 @@
+// PR c++/89686
+// { dg-do compile { target c++2a } }
+
+template <typename... Ts>
+void foo(Ts... xs)
+{
+  int i = 10;
+  [...xs...]{}(); // { dg-error "4:too many ..... in lambda capture" }
+  [...xs...=xs]{}(); // { dg-error "9:too many ..... in lambda 
capture|expected" }
+  [xs...]{}();
+  [...xs=xs]{}();
+
+  [i, ...xs...]{}(); // { dg-error "7:too many ..... in lambda capture" }
+  [i, ...xs...=xs]{}(); // { dg-error "12:too many ..... in lambda 
capture|expected" }
+  [i, xs...]{}();
+  [i, ...xs=xs]{}();
+}
+
+int main()
+{
+ foo(0, 1, 2);
+}

Reply via email to