Implement P0780R2, pack expansion in lambda init-capture.
Mostly this was straightforward; the tricky bit was finding, in the instantiation, the set of capture proxies built when instantiating the init-capture. The comment in lookup_init_capture_pack goes into detail. * parser.c (cp_parser_lambda_introducer): Parse pack init-capture. * pt.c (tsubst_pack_expansion): Handle init-capture packs. (lookup_init_capture_pack): New. (tsubst_expr) [DECL_EXPR]: Use it. (tsubst_lambda_expr): Remember field pack expansions for init-captures. From-SVN: r266052
This commit is contained in:
parent
16e723e600
commit
7de37c97b4
4 changed files with 120 additions and 11 deletions
|
@ -1,5 +1,13 @@
|
|||
2018-11-12 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement P0780R2, pack expansion in lambda init-capture.
|
||||
* parser.c (cp_parser_lambda_introducer): Parse pack init-capture.
|
||||
* pt.c (tsubst_pack_expansion): Handle init-capture packs.
|
||||
(lookup_init_capture_pack): New.
|
||||
(tsubst_expr) [DECL_EXPR]: Use it.
|
||||
(tsubst_lambda_expr): Remember field pack expansions for
|
||||
init-captures.
|
||||
|
||||
* cp-tree.h (struct cp_evaluated): New.
|
||||
* init.c (get_nsdmi): Use it.
|
||||
* parser.c (cp_parser_enclosed_template_argument_list): Use it.
|
||||
|
|
|
@ -10395,6 +10395,17 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
|
|||
continue;
|
||||
}
|
||||
|
||||
bool init_pack_expansion = false;
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
|
||||
{
|
||||
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
|
||||
if (cxx_dialect < cxx2a)
|
||||
pedwarn (loc, 0, "pack init-capture only available with "
|
||||
"-std=c++2a or -std=gnu++2a");
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
init_pack_expansion = true;
|
||||
}
|
||||
|
||||
/* Remember whether we want to capture as a reference or not. */
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_AND))
|
||||
{
|
||||
|
@ -10438,6 +10449,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
|
|||
error ("empty initializer for lambda init-capture");
|
||||
capture_init_expr = error_mark_node;
|
||||
}
|
||||
if (init_pack_expansion)
|
||||
capture_init_expr = make_pack_expansion (capture_init_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
93
gcc/cp/pt.c
93
gcc/cp/pt.c
|
@ -12151,7 +12151,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
|
|||
where it isn't expected). */
|
||||
unsubstituted_fn_pack = true;
|
||||
}
|
||||
else if (is_normal_capture_proxy (parm_pack))
|
||||
else if (is_capture_proxy (parm_pack))
|
||||
{
|
||||
arg_pack = retrieve_local_specialization (parm_pack);
|
||||
if (argument_pack_element_is_expansion_p (arg_pack, 0))
|
||||
|
@ -16769,6 +16769,55 @@ tsubst_decomp_names (tree decl, tree pattern_decl, tree args,
|
|||
return decl;
|
||||
}
|
||||
|
||||
/* Return the proper local_specialization for init-capture pack DECL. */
|
||||
|
||||
static tree
|
||||
lookup_init_capture_pack (tree decl)
|
||||
{
|
||||
/* We handle normal pack captures by forwarding to the specialization of the
|
||||
captured parameter. We can't do that for pack init-captures; we need them
|
||||
to have their own local_specialization. We created the individual
|
||||
VAR_DECLs (if any) under build_capture_proxy, and we need to collect them
|
||||
when we process the DECL_EXPR for the pack init-capture in the template.
|
||||
So, how do we find them? We don't know the capture proxy pack when
|
||||
building the individual resulting proxies, and we don't know the
|
||||
individual proxies when instantiating the pack. What we have in common is
|
||||
the FIELD_DECL.
|
||||
|
||||
So...when we instantiate the FIELD_DECL, we stick the result in
|
||||
local_specializations. Then at the DECL_EXPR we look up that result, see
|
||||
how many elements it has, synthesize the names, and look them up. */
|
||||
|
||||
tree cname = DECL_NAME (decl);
|
||||
tree val = DECL_VALUE_EXPR (decl);
|
||||
tree field = TREE_OPERAND (val, 1);
|
||||
gcc_assert (TREE_CODE (field) == FIELD_DECL);
|
||||
tree fpack = retrieve_local_specialization (field);
|
||||
if (fpack == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
int len = 1;
|
||||
tree vec = NULL_TREE;
|
||||
tree r = NULL_TREE;
|
||||
if (TREE_CODE (fpack) == TREE_VEC)
|
||||
{
|
||||
len = TREE_VEC_LENGTH (fpack);
|
||||
vec = make_tree_vec (len);
|
||||
r = make_node (NONTYPE_ARGUMENT_PACK);
|
||||
SET_ARGUMENT_PACK_ARGS (r, vec);
|
||||
}
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
tree ename = vec ? make_ith_pack_parameter_name (cname, i) : cname;
|
||||
tree elt = lookup_name_real (ename, 0, 0, true, 0, LOOKUP_NORMAL);
|
||||
if (vec)
|
||||
TREE_VEC_ELT (vec, i) = elt;
|
||||
else
|
||||
r = elt;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Like tsubst_copy for expressions, etc. but also does semantic
|
||||
processing. */
|
||||
|
||||
|
@ -16854,18 +16903,21 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
|||
/* We're in tsubst_lambda_expr, we've already inserted a new
|
||||
capture proxy, so look it up and register it. */
|
||||
tree inst;
|
||||
if (DECL_PACK_P (decl))
|
||||
if (!DECL_PACK_P (decl))
|
||||
{
|
||||
inst = lookup_name_real (DECL_NAME (decl), 0, 0,
|
||||
/*block_p=*/true, 0, LOOKUP_HIDDEN);
|
||||
gcc_assert (inst != decl && is_capture_proxy (inst));
|
||||
}
|
||||
else if (is_normal_capture_proxy (decl))
|
||||
{
|
||||
inst = (retrieve_local_specialization
|
||||
(DECL_CAPTURED_VARIABLE (decl)));
|
||||
gcc_assert (TREE_CODE (inst) == NONTYPE_ARGUMENT_PACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
inst = lookup_name_real (DECL_NAME (decl), 0, 0,
|
||||
/*block_p=*/true, 0, LOOKUP_HIDDEN);
|
||||
gcc_assert (inst != decl && is_capture_proxy (inst));
|
||||
}
|
||||
inst = lookup_init_capture_pack (decl);
|
||||
|
||||
register_local_specialization (inst, decl);
|
||||
break;
|
||||
}
|
||||
|
@ -17812,13 +17864,22 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
|
||||
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
|
||||
|
||||
vec<tree,va_gc>* field_packs = NULL;
|
||||
|
||||
for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;
|
||||
cap = TREE_CHAIN (cap))
|
||||
{
|
||||
tree field = TREE_PURPOSE (cap);
|
||||
if (PACK_EXPANSION_P (field))
|
||||
field = PACK_EXPANSION_PATTERN (field);
|
||||
field = tsubst_decl (field, args, complain);
|
||||
tree ofield = TREE_PURPOSE (cap);
|
||||
if (PACK_EXPANSION_P (ofield))
|
||||
ofield = PACK_EXPANSION_PATTERN (ofield);
|
||||
tree field = tsubst_decl (ofield, args, complain);
|
||||
|
||||
if (DECL_PACK_P (ofield) && !DECL_NORMAL_CAPTURE_P (ofield))
|
||||
{
|
||||
/* Remember these for when we've pushed local_specializations. */
|
||||
vec_safe_push (field_packs, ofield);
|
||||
vec_safe_push (field_packs, field);
|
||||
}
|
||||
|
||||
if (field == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
@ -17908,6 +17969,16 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
|
||||
tree body = start_lambda_function (fn, r);
|
||||
|
||||
/* Now record them for lookup_init_capture_pack. */
|
||||
int fplen = vec_safe_length (field_packs);
|
||||
for (int i = 0; i < fplen; )
|
||||
{
|
||||
tree pack = (*field_packs)[i++];
|
||||
tree inst = (*field_packs)[i++];
|
||||
register_local_specialization (inst, pack);
|
||||
}
|
||||
release_tree_vector (field_packs);
|
||||
|
||||
register_parameter_specializations (oldfn, fn);
|
||||
|
||||
if (oldtmpl)
|
||||
|
|
17
gcc/testsuite/g++.dg/cpp2a/lambda-pack-init1.C
Normal file
17
gcc/testsuite/g++.dg/cpp2a/lambda-pack-init1.C
Normal file
|
@ -0,0 +1,17 @@
|
|||
// { dg-do compile { target c++2a } }
|
||||
|
||||
void bar();
|
||||
void bar(int);
|
||||
|
||||
template <typename... Args>
|
||||
void foo(Args... args) {
|
||||
[...xs=args]{
|
||||
bar(xs...); // xs is an init-capture pack
|
||||
};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
foo(); // OK: xs contains zero init-captures
|
||||
foo(1); // OK: xs contains one init-capture
|
||||
}
|
Loading…
Add table
Reference in a new issue