aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/lambda.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-07-31 14:50:00 -0400
committerJason Merrill <jason@gcc.gnu.org>2019-07-31 14:50:00 -0400
commit10acaf4db9f8b54bd55fb7a6f5b6bb39a91fb9b8 (patch)
treed87b3e8faad065950a5e60c3ced44c3a27fada8c /gcc/cp/lambda.c
parentfc79fc4966060222486458e6b310203e4e8527a1 (diff)
downloadgcc-10acaf4db9f8b54bd55fb7a6f5b6bb39a91fb9b8.zip
gcc-10acaf4db9f8b54bd55fb7a6f5b6bb39a91fb9b8.tar.gz
gcc-10acaf4db9f8b54bd55fb7a6f5b6bb39a91fb9b8.tar.bz2
PR c++/90538 - multiple expansions of capture packs
Previously, with init-capture the type of the closure field was a DECLTYPE_TYPE of the initializer. But since each time we tsubst a lambda we get a different lambda, that meant that if the initializer is a lambda, we'd end up with different closure types in the field and initializer after substitution (PR 87322). We dealt with this by remembering the lambda instantiation within each pack expansion element, using local_specialization_stack to separate the elements. But that broke this testcase, because it lost lambda capture proxies that also use local_specializations. So, this patch removes the local_specializations changes from that patch and fixes 87322 differently, by giving init-capture fields 'auto' type and doing deduction later. There's a bit of a kludge to get the right number of fields by pretending that 'auto...' uses the parameter packs from the initializer, but it does the trick. * cp-tree.h (DECLTYPE_FOR_INIT_CAPTURE): Remove. * lambda.c (add_capture): Copy parameter packs from init. (lambda_capture_field_type): Always use auto for init-capture. * pt.c (uses_parameter_packs): Return tree. (tsubst) [DECLTYPE_TYPE]: Remove init-capture handling. (gen_elem_of_pack_expansion_instantiation): Don't push local_specialization_stack. (prepend_one_capture): New. (tsubst_lambda_expr): Use it. Don't touch local_specializations. (do_auto_deduction): Avoid redundant error. From-SVN: r273944
Diffstat (limited to 'gcc/cp/lambda.c')
-rw-r--r--gcc/cp/lambda.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 758773b..c4fed16 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -213,16 +213,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
tree type;
bool is_this = is_this_parameter (tree_strip_nop_conversions (expr));
- if (!is_this && type_dependent_expression_p (expr))
- {
- type = cxx_make_type (DECLTYPE_TYPE);
- DECLTYPE_TYPE_EXPR (type) = expr;
- DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
- DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p;
- DECLTYPE_FOR_REF_CAPTURE (type) = by_reference_p;
- SET_TYPE_STRUCTURAL_EQUALITY (type);
- }
- else if (!is_this && explicit_init_p)
+ if (!is_this && explicit_init_p)
{
tree auto_node = make_auto ();
@@ -233,6 +224,14 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
type = build_reference_type (type);
type = do_auto_deduction (type, expr, auto_node);
}
+ else if (!is_this && type_dependent_expression_p (expr))
+ {
+ type = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (type) = expr;
+ DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
+ DECLTYPE_FOR_REF_CAPTURE (type) = by_reference_p;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ }
else
{
type = non_reference (unlowered_expr_type (expr));
@@ -594,7 +593,16 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
name = get_identifier (buf);
if (variadic)
- type = make_pack_expansion (type);
+ {
+ type = make_pack_expansion (type);
+ if (explicit_init_p)
+ /* With an explicit initializer 'type' is auto, which isn't really a
+ 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);
+ }
/* Make member variable. */
member = build_decl (input_location, FIELD_DECL, name, type);