From 152d47df7f625885ae972386c759330cea6b169e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 21 Mar 2019 23:01:02 +0100 Subject: [PATCH] re PR c++/89767 (ICE with tuple and optimization) 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. * g++.dg/cpp1y/lambda-init18.C: New test. * g++.dg/cpp1y/lambda-init19.C: New test. * g++.dg/cpp1y/pr89767.C: New test. From-SVN: r269860 --- gcc/cp/ChangeLog | 9 ++++ gcc/cp/lambda.c | 15 ------ gcc/cp/parser.c | 55 ++++++++++++++++------ gcc/testsuite/ChangeLog | 7 +++ gcc/testsuite/g++.dg/cpp1y/lambda-init18.C | 12 +++++ gcc/testsuite/g++.dg/cpp1y/lambda-init19.C | 15 ++++++ gcc/testsuite/g++.dg/cpp1y/pr89767.C | 32 +++++++++++++ 7 files changed, 115 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-init18.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-init19.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr89767.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5a28c96d52a..741ad485352 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-03-21 Jakub Jelinek + + 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 PR c++/89571 diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index e7f0fda65be..3e176760ba5 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 81aff35cad9..c669e49214f 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 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 % 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 f575c0f59a9..2334e9736a2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-03-21 Jakub Jelinek + + 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 Cesar Philippidis 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 00000000000..5a866009e78 --- /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 00000000000..830ecc03a08 --- /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 00000000000..108de51926e --- /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 struct e { using g = d; }; +template class> using h = e; +template class i> +using j = typename h::g; +template int k(c); +template class au; +struct l { template using m = typename c::f; }; +struct s : l { using af = j *, m>; }; +template struct o; +template using q = typename o::g; +template struct r; +template struct r { typedef c aj; }; +template struct al { typename r::aj operator*(); void operator++(); }; +template +bool operator!=(al, al); +template struct ap; +template +struct ap : ap<1, as...> {}; +template struct ap {}; +template class au : public ap<0, at...> {}; +template +struct o> : o

> {}; +template struct o<0, au> { typedef ar g; }; +template constexpr ar av(ap __t) { return ar (); } +template constexpr q> aw(au __t) { av

(__t); return q> (); } +struct bg { typedef s::af af; }; +struct F { typedef al bk; bk begin(); bk end(); }; +void bo() { int t = 0; F cv; for (auto bp : cv) [t, n = k(aw<1>(bp))] {}; } -- 2.30.2