diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/lambda.c | 15 | ||||
-rw-r--r-- | gcc/cp/parser.c | 55 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/lambda-init18.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/lambda-init19.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/pr89767.C | 32 |
7 files changed, 115 insertions, 30 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5a28c96..741ad48 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-03-21 Jakub Jelinek <jakub@redhat.com> + + PR c++/89767 + * parser.c (cp_parser_lambda_introducer): Add ids and first_capture_id + variables, check for duplicates in this function. + * lambda.c (add_capture): Don't check for duplicates nor use + IDENTIFIER_MARKED. + (register_capture_members): Don't clear IDENTIFIER_MARKED here. + 2019-03-21 Paolo Carlini <paolo.carlini@oracle.com> PR c++/89571 diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index e7f0fda..3e17676 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -601,19 +601,6 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, IDENTIFIER_LENGTH (id) + 1); name = get_identifier (buf); - /* If TREE_TYPE isn't set, we're still in the introducer, so check - for duplicates. */ - if (!LAMBDA_EXPR_CLOSURE (lambda)) - { - if (IDENTIFIER_MARKED (name)) - { - pedwarn (input_location, 0, - "already captured %qD in lambda expression", id); - return NULL_TREE; - } - IDENTIFIER_MARKED (name) = true; - } - if (variadic) type = make_pack_expansion (type); @@ -674,8 +661,6 @@ register_capture_members (tree captures) if (PACK_EXPANSION_P (field)) field = PACK_EXPANSION_PATTERN (field); - /* We set this in add_capture to avoid duplicates. */ - IDENTIFIER_MARKED (DECL_NAME (field)) = false; finish_member_declaration (field); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 81aff35..c669e49 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10547,6 +10547,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) error ("non-local lambda expression cannot have a capture-default"); } + hash_set<tree, true> ids; + tree first_capture_id = NULL_TREE; while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)) { cp_token* capture_token; @@ -10582,11 +10584,14 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) pedwarn (loc, 0, "explicit by-copy capture of %<this%> redundant " "with by-copy capture default"); cp_lexer_consume_token (parser->lexer); - add_capture (lambda_expr, - /*id=*/this_identifier, - /*initializer=*/finish_this_expr (), - /*by_reference_p=*/true, - explicit_init_p); + if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr)) + pedwarn (input_location, 0, + "already captured %qD in lambda expression", + this_identifier); + else + add_capture (lambda_expr, /*id=*/this_identifier, + /*initializer=*/finish_this_expr (), + /*by_reference_p=*/true, explicit_init_p); continue; } @@ -10600,11 +10605,14 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) "%<-std=c++17%> or %<-std=gnu++17%>"); cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer); - add_capture (lambda_expr, - /*id=*/this_identifier, - /*initializer=*/finish_this_expr (), - /*by_reference_p=*/false, - explicit_init_p); + if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr)) + pedwarn (input_location, 0, + "already captured %qD in lambda expression", + this_identifier); + else + add_capture (lambda_expr, /*id=*/this_identifier, + /*initializer=*/finish_this_expr (), + /*by_reference_p=*/false, explicit_init_p); continue; } @@ -10753,11 +10761,28 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) "default", capture_id); } - add_capture (lambda_expr, - capture_id, - capture_init_expr, - /*by_reference_p=*/capture_kind == BY_REFERENCE, - explicit_init_p); + /* Check for duplicates. + Optimize for the zero or one explicit captures cases and only create + the hash_set after adding second capture. */ + bool found = false; + if (ids.elements ()) + found = ids.add (capture_id); + else if (first_capture_id == NULL_TREE) + first_capture_id = capture_id; + else if (capture_id == first_capture_id) + found = true; + else + { + ids.add (first_capture_id); + ids.add (capture_id); + } + if (found) + pedwarn (input_location, 0, + "already captured %qD in lambda expression", capture_id); + else + add_capture (lambda_expr, capture_id, capture_init_expr, + /*by_reference_p=*/capture_kind == BY_REFERENCE, + explicit_init_p); /* If there is any qualification still in effect, clear it now; we will be starting fresh with the next capture. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f575c0f..2334e97 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-03-21 Jakub Jelinek <jakub@redhat.com> + + PR c++/89767 + * g++.dg/cpp1y/lambda-init18.C: New test. + * g++.dg/cpp1y/lambda-init19.C: New test. + * g++.dg/cpp1y/pr89767.C: New test. + 2019-03-21 Thomas Schwinge <thomas@codesourcery.com> Cesar Philippidis <cesar@codesourcery.com> diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init18.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init18.C new file mode 100644 index 0000000..5a86600 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init18.C @@ -0,0 +1,12 @@ +// PR c++/89767 +// { dg-do compile { target c++14 } } + +void bar (int); + +void +foo () +{ + int x = 0; + auto z = [x, y = [x] { bar (x); }] { y (); bar (x); }; + z (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init19.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init19.C new file mode 100644 index 0000000..830ecc0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init19.C @@ -0,0 +1,15 @@ +// PR c++/89767 +// { dg-do compile { target c++14 } } + +void bar (int); + +void +foo () +{ + int x = 0; + int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0; + auto z = [x, y = [x] { bar (x); }, x] { y (); bar (x); }; // { dg-error "already captured 'x' in lambda expression" } + auto w = [x, a, b, c, d, y = [x] { bar (x); }, e, f, g, h, x] { y (); bar (x + a + b + c + d + e + f + g + h); }; // { dg-error "already captured 'x' in lambda expression" } + z (); + w (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr89767.C b/gcc/testsuite/g++.dg/cpp1y/pr89767.C new file mode 100644 index 0000000..108de51 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr89767.C @@ -0,0 +1,32 @@ +// PR c++/89767 +// { dg-do compile { target c++14 } } +// { dg-options "-O2 -Wall" } + +template <typename d> struct e { using g = d; }; +template <typename d, template <typename> class> using h = e<d>; +template <typename d, template <typename> class i> +using j = typename h<d, i>::g; +template <typename c> int k(c); +template <typename...> class au; +struct l { template <typename c> using m = typename c::f; }; +struct s : l { using af = j<au<int, int> *, m>; }; +template <unsigned long, typename> struct o; +template <long p, typename c> using q = typename o<p, c>::g; +template <typename> struct r; +template <typename c> struct r<c *> { typedef c aj; }; +template <typename ak, typename> struct al { typename r<ak>::aj operator*(); void operator++(); }; +template <typename am, typename an, typename ao> +bool operator!=(al<am, ao>, al<an, ao>); +template <unsigned long, typename...> struct ap; +template <unsigned long aq, typename ar, typename... as> +struct ap<aq, ar, as...> : ap<1, as...> {}; +template <unsigned long aq, typename ar> struct ap<aq, ar> {}; +template <typename... at> class au : public ap<0, at...> {}; +template <unsigned long p, typename ar, typename... as> +struct o<p, au<ar, as...>> : o<p - 1, au<as...>> {}; +template <typename ar, typename... as> struct o<0, au<ar, as...>> { typedef ar g; }; +template <long p, typename ar> constexpr ar av(ap<p, ar> __t) { return ar (); } +template <int p, typename... at> constexpr q<p, au<at...>> aw(au<at...> __t) { av<p>(__t); return q<p, au<at...>> (); } +struct bg { typedef s::af af; }; +struct F { typedef al<bg::af, int> bk; bk begin(); bk end(); }; +void bo() { int t = 0; F cv; for (auto bp : cv) [t, n = k(aw<1>(bp))] {}; } |