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