From: Jason Merrill Date: Fri, 2 Apr 2021 15:05:46 +0000 (-0400) Subject: c++: lambda pack init-capture within generic lambda X-Git-Tag: releases/gcc-9.4.0~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7168fb621b4442936d2a9429389a65f15043e5e4;p=thirdparty%2Fgcc.git 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. --- diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index be291e99ce64..f1106dd9188c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -443,6 +443,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: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -3622,6 +3623,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 38e9b2f8a5f1..1ee758140045 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -608,8 +608,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 20bc198efac2..612557bb717e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12447,12 +12447,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 000000000000..3ee500ed9996 --- /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); +}