From ffaf40c06df8ab043024fcfd3de7f45985b2aed1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 30 Aug 2019 14:29:13 +0200 Subject: [PATCH] backport: re PR c++/89767 (ICE with tuple and optimization) Backported from mainline 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. * 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: r275139 --- gcc/cp/ChangeLog | 9 +++ gcc/cp/lambda.c | 15 ----- gcc/cp/parser.c | 72 +++++++++++++++++----- 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, 132 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 0312b25d11bf..5d7aaa65eb0a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,6 +1,15 @@ 2019-08-30 Jakub Jelinek Backported from mainline + 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-14 Jakub Jelinek PR c++/89512 diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 2ead27d81762..fc7809d69eb9 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -567,19 +567,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); @@ -634,8 +621,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 a29b3940ab0e..7542a96dcac5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10010,6 +10010,11 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) first = false; } + hash_set *ids = NULL; +#if GCC_VERSION >= 7000 + char ids_buf[sizeof (hash_set) + __alignof__ (hash_set) - 1]; +#endif + tree first_capture_id = NULL_TREE; while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)) { cp_token* capture_token; @@ -10044,11 +10049,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; } @@ -10062,11 +10070,14 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) "-std=c++1z or -std=gnu++1z"); 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; } @@ -10190,13 +10201,44 @@ 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 && 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 + { +#if GCC_VERSION >= 7000 + ids = new (ids_buf + + (-(uintptr_t) ids_buf + & (__alignof__ (hash_set ) - 1))) hash_set ; +#else + ids = new hash_set ; +#endif + 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 (ids) +#if GCC_VERSION >= 7000 + ids->~hash_set (); +#else + delete ids; +#endif + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 10dd5579129c..21817bba375b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,13 @@ 2019-08-30 Jakub Jelinek Backported from mainline + 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-19 Jakub Jelinek PR target/89752 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 000000000000..5a866009e787 --- /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 000000000000..830ecc03a084 --- /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 000000000000..108de51926eb --- /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.47.2