Commit 2993d08a by Jason Merrill Committed by Jason Merrill

Core DR 904 PR c++/41933

	Core DR 904
	PR c++/41933
	* parser.c (cp_parser_lambda_introducer): Handle variadic capture.
	* lambda.c (add_capture): Handle variadic capture.
	(add_default_capture, lambda_capture_field_type): Likewise.
	(build_capture_proxy, register_capture_members): Likewise.
	* pt.c (register_specialization): Allow FIELD_DECL.
	(retrieve_specialization): Likewise.
	(find_parameter_packs_r): Handle FIELD_DECL and VAR_DECL.
	(tsubst_pack_expansion): Handle FIELD_DECL packs.
	(gen_elem_of_pack_expansion_instantiation): Likewise.
	(instantiate_class_template_1): Likewise.
	(tsubst_decl, tsubst_copy): Likewise.
	(tsubst_expr) [DECL_EXPR]: Handle capture proxy packs.
	(tsubst_copy_and_build) [VAR_DECL]: Likewise.
	* semantics.c (finish_non_static_data_member): Don't try to represent
	the type of a COMPOUND_REF of a FIELD_DECL pack.

From-SVN: r202605
parent 73f4e2d2
2013-09-15 Jason Merrill <jason@redhat.com>
Core DR 904
PR c++/41933
* parser.c (cp_parser_lambda_introducer): Handle variadic capture.
* lambda.c (add_capture): Handle variadic capture.
(add_default_capture, lambda_capture_field_type): Likewise.
(build_capture_proxy, register_capture_members): Likewise.
* pt.c (register_specialization): Allow FIELD_DECL.
(retrieve_specialization): Likewise.
(find_parameter_packs_r): Handle FIELD_DECL and VAR_DECL.
(tsubst_pack_expansion): Handle FIELD_DECL packs.
(gen_elem_of_pack_expansion_instantiation): Likewise.
(instantiate_class_template_1): Likewise.
(tsubst_decl, tsubst_copy): Likewise.
(tsubst_expr) [DECL_EXPR]: Handle capture proxy packs.
(tsubst_copy_and_build) [VAR_DECL]: Likewise.
* semantics.c (finish_non_static_data_member): Don't try to represent
the type of a COMPOUND_REF of a FIELD_DECL pack.
PR c++/41933
* cp-tree.h (DECL_PACK_P): Replace FUNCTION_PARAMETER_PACK_P.
* cxx-pretty-print.c (direct_declarator): Adjust.
......
......@@ -215,7 +215,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p)
}
else
type = non_reference (unlowered_expr_type (expr));
if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type))
if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type)
|| DECL_PACK_P (expr))
{
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
......@@ -320,15 +321,21 @@ tree
lambda_proxy_type (tree ref)
{
tree type;
if (ref == error_mark_node)
return error_mark_node;
if (REFERENCE_REF_P (ref))
ref = TREE_OPERAND (ref, 0);
gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
type = TREE_TYPE (ref);
if (type && !WILDCARD_TYPE_P (non_reference (type)))
return type;
if (!type || WILDCARD_TYPE_P (non_reference (type)))
{
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = ref;
DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
SET_TYPE_STRUCTURAL_EQUALITY (type);
}
if (DECL_PACK_P (TREE_OPERAND (ref, 1)))
type = make_pack_expansion (type);
return type;
}
......@@ -341,6 +348,9 @@ build_capture_proxy (tree member)
{
tree var, object, fn, closure, name, lam, type;
if (PACK_EXPANSION_P (member))
member = PACK_EXPANSION_PATTERN (member);
closure = DECL_CONTEXT (member);
fn = lambda_function (closure);
lam = CLASSTYPE_LAMBDA_EXPR (closure);
......@@ -422,12 +432,20 @@ vla_capture_type (tree array_type)
and return it. */
tree
add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
bool explicit_init_p)
{
char *buf;
tree type, member, name;
bool vla = false;
bool variadic = false;
tree initializer = orig_init;
if (PACK_EXPANSION_P (initializer))
{
initializer = PACK_EXPANSION_PATTERN (initializer);
variadic = true;
}
if (TREE_CODE (initializer) == TREE_LIST)
initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
......@@ -498,6 +516,9 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
IDENTIFIER_MARKED (name) = true;
}
if (variadic)
type = make_pack_expansion (type);
/* Make member variable. */
member = build_decl (input_location, FIELD_DECL, name, type);
DECL_VLA_CAPTURE_P (member) = vla;
......@@ -518,8 +539,14 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
&& current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
finish_member_declaration (member);
tree listmem = member;
if (variadic)
{
listmem = make_pack_expansion (member);
initializer = orig_init;
}
LAMBDA_EXPR_CAPTURE_LIST (lambda)
= tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
= tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
if (LAMBDA_EXPR_CLOSURE (lambda))
return build_capture_proxy (member);
......@@ -538,9 +565,14 @@ register_capture_members (tree captures)
return;
register_capture_members (TREE_CHAIN (captures));
tree field = TREE_PURPOSE (captures);
if (PACK_EXPANSION_P (field))
field = PACK_EXPANSION_PATTERN (field);
/* We set this in add_capture to avoid duplicates. */
IDENTIFIER_MARKED (DECL_NAME (TREE_PURPOSE (captures))) = false;
finish_member_declaration (TREE_PURPOSE (captures));
IDENTIFIER_MARKED (DECL_NAME (field)) = false;
finish_member_declaration (field);
}
/* Similar to add_capture, except this works on a stack of nested lambdas.
......@@ -565,6 +597,8 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
tree lambda = TREE_VALUE (node);
current_class_type = LAMBDA_EXPR_CLOSURE (lambda);
if (DECL_PACK_P (initializer))
initializer = make_pack_expansion (initializer);
var = add_capture (lambda,
id,
initializer,
......
......@@ -8753,6 +8753,14 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
/*template_arg_p=*/false,
&error_msg,
capture_token->location);
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
{
cp_lexer_consume_token (parser->lexer);
capture_init_expr = make_pack_expansion (capture_init_expr);
}
else
check_for_bare_parameter_packs (capture_init_expr);
}
if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE
......
......@@ -1004,7 +1004,10 @@ optimize_specialization_lookup_p (tree tmpl)
If TMPL is a type template and CLASS_SPECIALIZATIONS_P is true,
then we search for a partial specialization matching ARGS. This
parameter is ignored if TMPL is not a class template. */
parameter is ignored if TMPL is not a class template.
We can also look up a FIELD_DECL, if it is a lambda capture pack; the
result is a NONTYPE_ARGUMENT_PACK. */
static tree
retrieve_specialization (tree tmpl, tree args, hashval_t hash)
......@@ -1015,12 +1018,15 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash)
if (args == error_mark_node)
return NULL_TREE;
gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL
|| TREE_CODE (tmpl) == FIELD_DECL);
/* There should be as many levels of arguments as there are
levels of parameters. */
gcc_assert (TMPL_ARGS_DEPTH (args)
== TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)));
== (TREE_CODE (tmpl) == TEMPLATE_DECL
? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
: template_class_depth (DECL_CONTEXT (tmpl))));
if (optimize_specialization_lookup_p (tmpl))
{
......@@ -1311,7 +1317,10 @@ is_specialization_of_friend (tree decl, tree friend_decl)
/* Register the specialization SPEC as a specialization of TMPL with
the indicated ARGS. IS_FRIEND indicates whether the specialization
is actually just a friend declaration. Returns SPEC, or an
equivalent prior declaration, if available. */
equivalent prior declaration, if available.
We also store instantiations of field packs in the hash table, even
though they are not themselves templates, to make lookup easier. */
static tree
register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
......@@ -1321,7 +1330,9 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
void **slot = NULL;
spec_entry elt;
gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec));
gcc_assert ((TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec))
|| (TREE_CODE (tmpl) == FIELD_DECL
&& TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK));
if (TREE_CODE (spec) == FUNCTION_DECL
&& uses_template_parms (DECL_TI_ARGS (spec)))
......@@ -1443,7 +1454,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
/* A specialization must be declared in the same namespace as the
template it is specializing. */
if (DECL_TEMPLATE_SPECIALIZATION (spec)
if (DECL_P (spec) && DECL_TEMPLATE_SPECIALIZATION (spec)
&& !check_specialization_namespace (tmpl))
DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl);
......@@ -3084,6 +3095,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
parameter_pack_p = true;
break;
case FIELD_DECL:
case PARM_DECL:
if (DECL_PACK_P (t))
{
......@@ -3094,6 +3106,18 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
}
break;
/* Look through a lambda capture proxy to the field pack. */
case VAR_DECL:
if (DECL_HAS_VALUE_EXPR_P (t))
{
tree v = DECL_VALUE_EXPR (t);
cp_walk_tree (&v,
&find_parameter_packs_r,
ppd, ppd->visited);
*walk_subtrees = 0;
}
break;
case BASES:
parameter_pack_p = true;
break;
......@@ -8913,6 +8937,8 @@ instantiate_class_template_1 (tree type)
else if (TREE_CODE (t) != CONST_DECL)
{
tree r;
tree vec = NULL_TREE;
int len = 1;
/* The file and line for this declaration, to
assist in error message reporting. Since we
......@@ -8925,6 +8951,18 @@ instantiate_class_template_1 (tree type)
r = tsubst (t, args, tf_warning_or_error, NULL_TREE);
if (TREE_CODE (t) == TEMPLATE_DECL)
--processing_template_decl;
if (TREE_CODE (r) == TREE_VEC)
{
/* A capture pack became multiple fields. */
vec = r;
len = TREE_VEC_LENGTH (vec);
}
for (int i = 0; i < len; ++i)
{
if (vec)
r = TREE_VEC_ELT (vec, i);
if (VAR_P (r))
{
/* In [temp.inst]:
......@@ -8951,8 +8989,8 @@ instantiate_class_template_1 (tree type)
else if (TREE_CODE (r) == FIELD_DECL)
{
/* Determine whether R has a valid type and can be
completed later. If R is invalid, then its type is
replaced by error_mark_node. */
completed later. If R is invalid, then its type
is replaced by error_mark_node. */
tree rtype = TREE_TYPE (r);
if (can_complete_type_without_circularity (rtype))
complete_type (rtype);
......@@ -8978,6 +9016,7 @@ instantiate_class_template_1 (tree type)
}
}
}
}
else
{
if (TYPE_P (t) || DECL_CLASS_TEMPLATE_P (t)
......@@ -9367,7 +9406,8 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
argument_pack_element_is_expansion_p (arg_pack, index);
/* Select the Ith argument from the pack. */
if (TREE_CODE (parm) == PARM_DECL)
if (TREE_CODE (parm) == PARM_DECL
|| TREE_CODE (parm) == FIELD_DECL)
{
if (index == 0)
{
......@@ -9481,6 +9521,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
need_local_specializations = true;
}
}
else if (TREE_CODE (parm_pack) == FIELD_DECL)
arg_pack = tsubst_copy (parm_pack, args, complain, in_decl);
else
{
int idx;
......@@ -9605,7 +9647,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
{
tree parm = TREE_PURPOSE (pack);
if (TREE_CODE (parm) == PARM_DECL)
if (TREE_CODE (parm) == PARM_DECL
|| TREE_CODE (parm) == FIELD_DECL)
register_local_specialization (TREE_TYPE (pack), parm);
else
{
......@@ -10572,10 +10615,44 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
case FIELD_DECL:
{
tree type;
tree type = NULL_TREE;
tree vec = NULL_TREE;
tree expanded_types = NULL_TREE;
int len = 1;
if (PACK_EXPANSION_P (TREE_TYPE (t)))
{
/* This field is a lambda capture pack. Return a TREE_VEC of
the expanded fields to instantiate_class_template_1 and
store them in the specializations hash table as a
NONTYPE_ARGUMENT_PACK so that tsubst_copy can find them. */
expanded_types = tsubst_pack_expansion (TREE_TYPE (t), args,
complain, in_decl);
if (TREE_CODE (expanded_types) == TREE_VEC)
{
len = TREE_VEC_LENGTH (expanded_types);
vec = make_tree_vec (len);
}
else
{
/* All we did was update the type. Make a note of that. */
type = expanded_types;
expanded_types = NULL_TREE;
}
}
for (int i = 0; i < len; ++i)
{
r = copy_decl (t);
if (expanded_types)
{
type = TREE_VEC_ELT (expanded_types, i);
DECL_NAME (r)
= make_ith_pack_parameter_name (DECL_NAME (r), i);
}
else if (!type)
type = tsubst (TREE_TYPE (t), args, complain, in_decl);
if (type == error_mark_node)
RETURN (error_mark_node);
TREE_TYPE (r) = type;
......@@ -10605,6 +10682,21 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
args, complain, in_decl);
if (vec)
TREE_VEC_ELT (vec, i) = r;
}
if (vec)
{
r = vec;
tree pack = make_node (NONTYPE_ARGUMENT_PACK);
tree tpack = cxx_make_type (TYPE_ARGUMENT_PACK);
SET_ARGUMENT_PACK_ARGS (pack, vec);
SET_ARGUMENT_PACK_ARGS (tpack, expanded_types);
TREE_TYPE (pack) = tpack;
register_specialization (pack, t, args, false, 0);
}
}
break;
......@@ -12261,6 +12353,23 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return t;
case FIELD_DECL:
if (PACK_EXPANSION_P (TREE_TYPE (t)))
{
/* Check for a local specialization set up by
tsubst_pack_expansion. */
tree r = retrieve_local_specialization (t);
if (r)
{
if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
r = ARGUMENT_PACK_SELECT_ARG (r);
return r;
}
/* Otherwise return the full NONTYPE_ARGUMENT_PACK that
tsubst_decl put in the hash table. */
return retrieve_specialization (t, args, 0);
}
if (DECL_CONTEXT (t))
{
tree ctx;
......@@ -13020,6 +13129,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
else
do_local_using_decl (decl, scope, name);
}
else if (DECL_PACK_P (decl))
{
/* Don't build up decls for a variadic capture proxy, we'll
instantiate the elements directly as needed. */
break;
}
else
{
init = DECL_INITIAL (decl);
......@@ -14585,6 +14700,14 @@ tsubst_copy_and_build (tree t,
case VAR_DECL:
if (!args)
RETURN (t);
else if (DECL_PACK_P (t))
{
/* We don't build decls for an instantiation of a
variadic capture proxy, we instantiate the elements
when needed. */
gcc_assert (DECL_HAS_VALUE_EXPR_P (t));
return RECUR (DECL_VALUE_EXPR (t));
}
/* Fall through */
case PARM_DECL:
......
......@@ -1604,6 +1604,9 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
if (TREE_CODE (type) == REFERENCE_TYPE)
/* Quals on the object don't matter. */;
else if (PACK_EXPANSION_P (type))
/* Don't bother trying to represent this. */
type = NULL_TREE;
else
{
/* Set the cv qualifiers. */
......
// { dg-do run { target c++11 } }
int g() { return 0; }
template <class T, class... U>
int g(T t, U... u)
{
return t + g(u...);
}
template <class... T>
int f1(T... t)
{
return [t...] {
return g(t...);
}();
}
template <class... T>
int f2(T... t)
{
return [&t...] {
return g(t...);
}();
}
template <class... T>
int f3(T... t)
{
return [=] {
return g(t...);
}();
}
template <class... T>
int f4(T... t)
{
return [&] {
return g(t...);
}();
}
#define assert(E) do { if (!(E)) __builtin_abort(); } while(0)
int main()
{
assert (f1() == 0);
assert (f2() == 0);
assert (f3() == 0);
assert (f4() == 0);
assert (f1(42) == 42);
assert (f2(42) == 42);
assert (f3(42) == 42);
assert (f4(42) == 42);
assert (f1(1,2,3) == 6);
assert (f2(1,2,3) == 6);
assert (f3(1,2,3) == 6);
assert (f4(1,2,3) == 6);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment