}
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;
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;
- type = cxx_make_type (DECLTYPE_TYPE);
- DECLTYPE_TYPE_EXPR (type) = ref;
- DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
- SET_TYPE_STRUCTURAL_EQUALITY (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;
}
{
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);
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,
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;
&& 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);
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.
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,
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)
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))
{
/* 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,
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)))
/* 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);
parameter_pack_p = true;
break;
+ case FIELD_DECL:
case PARM_DECL:
if (DECL_PACK_P (t))
{
}
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;
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
r = tsubst (t, args, tf_warning_or_error, NULL_TREE);
if (TREE_CODE (t) == TEMPLATE_DECL)
--processing_template_decl;
- if (VAR_P (r))
+
+ if (TREE_CODE (r) == TREE_VEC)
{
- /* In [temp.inst]:
-
- [t]he initialization (and any associated
- side-effects) of a static data member does
- not occur unless the static data member is
- itself used in a way that requires the
- definition of the static data member to
- exist.
-
- Therefore, we do not substitute into the
- initialized for the static data member here. */
- finish_static_data_member_decl
- (r,
- /*init=*/NULL_TREE,
- /*init_const_expr_p=*/false,
- /*asmspec_tree=*/NULL_TREE,
- /*flags=*/0);
- /* Instantiate members marked with attribute used. */
- if (r != error_mark_node && DECL_PRESERVE_P (r))
- mark_used (r);
+ /* A capture pack became multiple fields. */
+ vec = r;
+ len = TREE_VEC_LENGTH (vec);
}
- else if (TREE_CODE (r) == FIELD_DECL)
+
+ for (int i = 0; i < len; ++i)
{
- /* 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. */
- tree rtype = TREE_TYPE (r);
- if (can_complete_type_without_circularity (rtype))
- complete_type (rtype);
-
- if (!COMPLETE_TYPE_P (rtype))
+ if (vec)
+ r = TREE_VEC_ELT (vec, i);
+ if (VAR_P (r))
{
- cxx_incomplete_type_error (r, rtype);
- TREE_TYPE (r) = error_mark_node;
+ /* In [temp.inst]:
+
+ [t]he initialization (and any associated
+ side-effects) of a static data member does
+ not occur unless the static data member is
+ itself used in a way that requires the
+ definition of the static data member to
+ exist.
+
+ Therefore, we do not substitute into the
+ initialized for the static data member here. */
+ finish_static_data_member_decl
+ (r,
+ /*init=*/NULL_TREE,
+ /*init_const_expr_p=*/false,
+ /*asmspec_tree=*/NULL_TREE,
+ /*flags=*/0);
+ /* Instantiate members marked with attribute used. */
+ if (r != error_mark_node && DECL_PRESERVE_P (r))
+ mark_used (r);
+ }
+ 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. */
+ tree rtype = TREE_TYPE (r);
+ if (can_complete_type_without_circularity (rtype))
+ complete_type (rtype);
+
+ if (!COMPLETE_TYPE_P (rtype))
+ {
+ cxx_incomplete_type_error (r, rtype);
+ TREE_TYPE (r) = error_mark_node;
+ }
}
- }
- /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE,
- such a thing will already have been added to the field
- list by tsubst_enum in finish_member_declaration in the
- CLASSTYPE_NESTED_UTDS case above. */
- if (!(TREE_CODE (r) == TYPE_DECL
- && TREE_CODE (TREE_TYPE (r)) == ENUMERAL_TYPE
- && DECL_ARTIFICIAL (r)))
- {
- set_current_access_from_decl (r);
- finish_member_declaration (r);
+ /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE,
+ such a thing will already have been added to the field
+ list by tsubst_enum in finish_member_declaration in the
+ CLASSTYPE_NESTED_UTDS case above. */
+ if (!(TREE_CODE (r) == TYPE_DECL
+ && TREE_CODE (TREE_TYPE (r)) == ENUMERAL_TYPE
+ && DECL_ARTIFICIAL (r)))
+ {
+ set_current_access_from_decl (r);
+ finish_member_declaration (r);
+ }
}
}
}
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)
{
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;
{
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
{
case FIELD_DECL:
{
- tree type;
+ tree type = NULL_TREE;
+ tree vec = NULL_TREE;
+ tree expanded_types = NULL_TREE;
+ int len = 1;
- r = copy_decl (t);
- type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- if (type == error_mark_node)
- RETURN (error_mark_node);
- TREE_TYPE (r) = type;
- cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+ 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;
+ }
+ }
- if (DECL_C_BIT_FIELD (r))
- /* For bit-fields, DECL_INITIAL gives the number of bits. For
- non-bit-fields DECL_INITIAL is a non-static data member
- initializer, which gets deferred instantiation. */
- DECL_INITIAL (r)
- = tsubst_expr (DECL_INITIAL (t), args,
- complain, in_decl,
- /*integral_constant_expression_p=*/true);
- else if (DECL_INITIAL (t))
+ for (int i = 0; i < len; ++i)
{
- /* Set up DECL_TEMPLATE_INFO so that we can get at the
- NSDMI in perform_member_init. Still set DECL_INITIAL
- so that we know there is one. */
- DECL_INITIAL (r) = void_zero_node;
- gcc_assert (DECL_LANG_SPECIFIC (r) == NULL);
- retrofit_lang_decl (r);
- DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+ 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;
+ cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+
+ if (DECL_C_BIT_FIELD (r))
+ /* For bit-fields, DECL_INITIAL gives the number of bits. For
+ non-bit-fields DECL_INITIAL is a non-static data member
+ initializer, which gets deferred instantiation. */
+ DECL_INITIAL (r)
+ = tsubst_expr (DECL_INITIAL (t), args,
+ complain, in_decl,
+ /*integral_constant_expression_p=*/true);
+ else if (DECL_INITIAL (t))
+ {
+ /* Set up DECL_TEMPLATE_INFO so that we can get at the
+ NSDMI in perform_member_init. Still set DECL_INITIAL
+ so that we know there is one. */
+ DECL_INITIAL (r) = void_zero_node;
+ gcc_assert (DECL_LANG_SPECIFIC (r) == NULL);
+ retrofit_lang_decl (r);
+ DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+ }
+ /* We don't have to set DECL_CONTEXT here; it is set by
+ finish_member_declaration. */
+ DECL_CHAIN (r) = NULL_TREE;
+
+ apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
+ args, complain, in_decl);
+
+ if (vec)
+ TREE_VEC_ELT (vec, i) = r;
}
- /* We don't have to set DECL_CONTEXT here; it is set by
- finish_member_declaration. */
- DECL_CHAIN (r) = NULL_TREE;
- apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
- args, complain, in_decl);
+ 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;
{
/* It may seem that this case cannot occur, since:
- typedef void f();
- void g() { f x; }
+ typedef void f();
+ void g() { f x; }
declares a function, not a variable. However:
- typedef void f();
- template <typename T> void g() { T t; }
- template void g<f>();
+ typedef void f();
+ template <typename T> void g() { T t; }
+ template void g<f>();
is an attempt to declare a variable with function
type. */
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;
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);
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: