aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2013-09-15 15:34:42 -0400
committerJason Merrill <jason@gcc.gnu.org>2013-09-15 15:34:42 -0400
commit2993d08a0f9053d6b434f550c489d2cc9af81c46 (patch)
tree1ea5c1ef411fbda7152061fe7ec9543ea81fc0b7 /gcc
parent73f4e2d261705d356b2283ae1576e495b74e7992 (diff)
downloadgcc-2993d08a0f9053d6b434f550c489d2cc9af81c46.zip
gcc-2993d08a0f9053d6b434f550c489d2cc9af81c46.tar.gz
gcc-2993d08a0f9053d6b434f550c489d2cc9af81c46.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog18
-rw-r--r--gcc/cp/lambda.c56
-rw-r--r--gcc/cp/parser.c8
-rw-r--r--gcc/cp/pt.c291
-rw-r--r--gcc/cp/semantics.c3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C57
6 files changed, 338 insertions, 95 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9234ade..c3c2edeb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,23 @@
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.
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index bf75834..1af301d 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -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;
- 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;
}
@@ -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,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e00e56c..2b0695a 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ecae904..2ef160a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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,55 +8951,68 @@ 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 (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);
+ }
}
}
}
@@ -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,39 +10615,88 @@ 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;
- 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;
@@ -10753,14 +10845,14 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
{
/* 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. */
@@ -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:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6d7f55f..0299b69 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C
new file mode 100644
index 0000000..fab1f6c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C
@@ -0,0 +1,57 @@
+// { 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);
+}