This patch fixes one of the few remaining holes in GCC's C++11 support:
lambda capture of a variadic function parameter pack. The
implementation involves introducing the internal notion of a FIELD_DECL
pack, even though such a thing can not be written explicitly in C++11.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 85cb3c43f2b8aa7897b499e125a5d77e7a8a5a3c
Author: Jason Merrill <ja...@redhat.com>
Date: Sun Sep 15 08:56:42 2013 -0700
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.
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);
+}
commit 2ed46e10e051a3cabf6dbb47567c85e012e50ab8
Author: Jason Merrill <ja...@redhat.com>
Date: Sat Sep 14 10:49:38 2013 -0700
PR c++/41933
* cp-tree.h (DECL_PACK_P): Replace FUNCTION_PARAMETER_PACK_P.
* cxx-pretty-print.c (direct_declarator): Adjust.
* decl2.c (cp_build_parm_decl): Adjust.
* pt.c (function_parameter_pack_p): Adjust.
(find_parameter_packs_r, push_template_decl_real): Adjust.
(tsubst_pack_expansion, tsubst_decl): Adjust.
(regenerate_decl_from_template, instantiate_decl): Adjust.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0d8bd95..4680053 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -138,7 +138,6 @@ c-common.h, not after.
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
- FUNCTION_PARAMETER_PACK_P (in PARM_DECL)
USING_DECL_TYPENAME_P (in USING_DECL)
DECL_VLA_CAPTURE_P (in FIELD_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
@@ -2874,10 +2873,9 @@ extern void decl_shadowed_for_var_insert (tree, tree);
the class definition is complete. */
#define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
-/* Determine if a parameter (i.e., a PARM_DECL) is a function
- parameter pack. */
-#define FUNCTION_PARAMETER_PACK_P(NODE) \
- (DECL_LANG_FLAG_1 (PARM_DECL_CHECK (NODE)))
+/* Determine if a declaration (PARM_DECL or FIELD_DECL) is a pack. */
+#define DECL_PACK_P(NODE) \
+ (DECL_P (NODE) && PACK_EXPANSION_P (TREE_TYPE (NODE)))
/* Determines if NODE is an expansion of one or more parameter packs,
e.g., a TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION. */
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 86d8b47..bcef876 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -1527,7 +1527,7 @@ cxx_pretty_printer::direct_declarator (tree t)
{
pp_cxx_space_for_pointer_operator (this, TREE_TYPE (t));
- if ((TREE_CODE (t) == PARM_DECL && FUNCTION_PARAMETER_PACK_P (t))
+ if ((TREE_CODE (t) == PARM_DECL && DECL_PACK_P (t))
|| template_parameter_pack_p (t))
/* A function parameter pack or non-type template
parameter pack. */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index d5d2912..c518551 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -188,11 +188,6 @@ cp_build_parm_decl (tree name, tree type)
if (!processing_template_decl)
DECL_ARG_TYPE (parm) = type_passed_as (type);
- /* If the type is a pack expansion, then we have a function
- parameter pack. */
- if (type && TREE_CODE (type) == TYPE_PACK_EXPANSION)
- FUNCTION_PARAMETER_PACK_P (parm) = 1;
-
return parm;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fed004c..ecae904 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2852,7 +2852,7 @@ bool
function_parameter_pack_p (const_tree t)
{
if (t && TREE_CODE (t) == PARM_DECL)
- return FUNCTION_PARAMETER_PACK_P (t);
+ return DECL_PACK_P (t);
return false;
}
@@ -3085,7 +3085,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
break;
case PARM_DECL:
- if (FUNCTION_PARAMETER_PACK_P (t))
+ if (DECL_PACK_P (t))
{
/* We don't want to walk into the type of a PARM_DECL,
because we don't want to see the type parameter pack. */
@@ -4646,7 +4646,7 @@ push_template_decl_real (tree decl, bool is_friend)
while (arg && argtype)
{
- if (!FUNCTION_PARAMETER_PACK_P (arg)
+ if (!DECL_PACK_P (arg)
&& check_for_bare_parameter_packs (TREE_TYPE (arg)))
{
/* This is a PARM_DECL that contains unexpanded parameter
@@ -9472,7 +9472,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
have the wrong value for a recursive call. Just make a
dummy decl, since it's only used for its type. */
arg_pack = tsubst_decl (parm_pack, args, complain);
- if (arg_pack && FUNCTION_PARAMETER_PACK_P (arg_pack))
+ if (arg_pack && DECL_PACK_P (arg_pack))
/* Partial instantiation of the parm_pack, we can't build
up an argument pack yet. */
arg_pack = NULL_TREE;
@@ -10465,7 +10465,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
tree prev_r = NULL_TREE;
tree first_r = NULL_TREE;
- if (FUNCTION_PARAMETER_PACK_P (t))
+ if (DECL_PACK_P (t))
{
/* If there is a local specialization that isn't a
parameter pack, it means that we're doing a "simple"
@@ -10515,10 +10515,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
/* We're on the Ith parameter of the function parameter
pack. */
{
- /* An argument of a function parameter pack is not a parameter
- pack. */
- FUNCTION_PARAMETER_PACK_P (r) = false;
-
/* Get the Ith type. */
type = TREE_VEC_ELT (expanded_types, i);
@@ -18705,7 +18701,7 @@ regenerate_decl_from_template (tree decl, tree tmpl)
pattern_parm
= skip_artificial_parms_for (code_pattern,
DECL_ARGUMENTS (code_pattern));
- while (decl_parm && !FUNCTION_PARAMETER_PACK_P (pattern_parm))
+ while (decl_parm && !DECL_PACK_P (pattern_parm))
{
tree parm_type;
tree attributes;
@@ -18728,7 +18724,7 @@ regenerate_decl_from_template (tree decl, tree tmpl)
}
/* Merge any parameters that match with the function parameter
pack. */
- if (pattern_parm && FUNCTION_PARAMETER_PACK_P (pattern_parm))
+ if (pattern_parm && DECL_PACK_P (pattern_parm))
{
int i, len;
tree expanded_types;
@@ -19247,7 +19243,7 @@ instantiate_decl (tree d, int defer_ok,
}
for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
{
- if (!FUNCTION_PARAMETER_PACK_P (tmpl_parm))
+ if (!DECL_PACK_P (tmpl_parm))
{
register_local_specialization (spec_parm, tmpl_parm);
spec_parm = DECL_CHAIN (spec_parm);
commit 76b473356bfd7c7a1192b8756dec5f20890e23f1
Author: Jason Merrill <ja...@redhat.com>
Date: Sun Sep 15 08:12:38 2013 -0700
* lambda.c (add_capture): Don't add DECL_LANG_SPECIFIC.
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index a53e692..bf75834 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -499,7 +499,7 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
}
/* Make member variable. */
- member = build_lang_decl (FIELD_DECL, name, type);
+ member = build_decl (input_location, FIELD_DECL, name, type);
DECL_VLA_CAPTURE_P (member) = vla;
if (!explicit_init_p)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d560e3c..fed004c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10500,7 +10500,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
}
}
- /* Loop through all of the parameter's we'll build. When T is
+ /* Loop through all of the parameters we'll build. When T is
a function parameter pack, LEN is the number of expanded
types in EXPANDED_TYPES; otherwise, LEN is 1. */
r = NULL_TREE;