From 2a26351b598242c2fbce95d2a0baacce0084aec6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Apr 2021 11:05:46 -0400 Subject: [PATCH] c++: lambda pack init-capture within generic lambda We represent the type of a pack init-capture as auto... with packs from the initializer stuck into PACK_EXPANSION_PARAMETER_PACKS so that expanding it produces the right number of elements. But when partially instantiating the auto..., we were changing PACK_EXPANSION_PARAMETER_PACKS to refer to only the auto itself. Fixed thus. gcc/cp/ChangeLog: PR c++/97938 * cp-tree.h (PACK_EXPANSION_AUTO_P): New. * lambda.c (add_capture): Set it. * pt.c (tsubst_pack_expansion): Handle it. gcc/testsuite/ChangeLog: PR c++/97938 * g++.dg/cpp2a/lambda-pack-init6.C: New test. --- gcc/cp/cp-tree.h | 4 ++++ gcc/cp/lambda.c | 7 +++++-- gcc/cp/pt.c | 19 ++++++++++++++---- gcc/testsuite/g++.dg/cpp2a/lambda-pack-init6.C | 27 ++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-pack-init6.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 66bba7b..a5d9d7a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -481,6 +481,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; SWITCH_STMT_NO_BREAK_P (in SWITCH_STMT) LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR) IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR) + PACK_EXPANSION_AUTO_P (in *_PACK_EXPANSION) 3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR) ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -3855,6 +3856,9 @@ struct GTY(()) lang_decl { /* True iff this pack expansion is for sizeof.... */ #define PACK_EXPANSION_SIZEOF_P(NODE) TREE_LANG_FLAG_1 (NODE) +/* True iff this pack expansion is for auto... in lambda init-capture. */ +#define PACK_EXPANSION_AUTO_P(NODE) TREE_LANG_FLAG_2 (NODE) + /* True iff the wildcard can match a template parameter pack. */ #define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE) diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 421685c..b0fd6ec 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -606,8 +606,11 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, parameter pack in this context. We will want as many fields as we have elements in the expansion of the initializer, so use its packs instead. */ - PACK_EXPANSION_PARAMETER_PACKS (type) - = uses_parameter_packs (initializer); + { + PACK_EXPANSION_PARAMETER_PACKS (type) + = uses_parameter_packs (initializer); + PACK_EXPANSION_AUTO_P (type) = true; + } } /* Make member variable. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7956e83..524a16a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13114,12 +13114,23 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, pattern and return a PACK_EXPANSION_*. The caller will need to deal with that. */ if (TREE_CODE (t) == EXPR_PACK_EXPANSION) - t = tsubst_expr (pattern, args, complain, in_decl, + result = tsubst_expr (pattern, args, complain, in_decl, /*integral_constant_expression_p=*/false); else - t = tsubst (pattern, args, complain, in_decl); - t = make_pack_expansion (t, complain); - return t; + result = tsubst (pattern, args, complain, in_decl); + result = make_pack_expansion (result, complain); + if (PACK_EXPANSION_AUTO_P (t)) + { + /* This is a fake auto... pack expansion created in add_capture with + _PACKS that don't appear in the pattern. Copy one over. */ + packs = PACK_EXPANSION_PARAMETER_PACKS (t); + pack = retrieve_local_specialization (TREE_VALUE (packs)); + gcc_checking_assert (DECL_PACK_P (pack)); + PACK_EXPANSION_PARAMETER_PACKS (result) + = build_tree_list (NULL_TREE, pack); + PACK_EXPANSION_AUTO_P (result) = true; + } + return result; } gcc_assert (len >= 0); diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init6.C b/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init6.C new file mode 100644 index 0000000..3ee500e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init6.C @@ -0,0 +1,27 @@ +// PR c++/97938 +// { dg-do compile { target c++20 } } + +template +int sink(Args&&... args) { return 2; } + +auto fwd1(const auto&&... ts1) { + return + [...ts1 = ts1] { + return sink(ts1...); + }(); +} + +template +auto fwd2(const T1& t1) { + return + [] (auto&&... ts1) { + return + [...ts1 = ts1] { + return sink(ts1...); + }(); + }(); +} + +int main() { + return fwd1() + fwd2(1); +} -- 2.7.4