From 2993d08a0f9053d6b434f550c489d2cc9af81c46 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 15 Sep 2013 15:34:42 -0400 Subject: 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 --- gcc/cp/ChangeLog | 18 ++ gcc/cp/lambda.c | 56 +++- gcc/cp/parser.c | 8 + gcc/cp/pt.c | 291 +++++++++++++++------ gcc/cp/semantics.c | 3 + .../g++.dg/cpp0x/lambda/lambda-variadic2.C | 57 ++++ 6 files changed, 338 insertions(+), 95 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C (limited to 'gcc') 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 + 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 void g() { T t; } - template void g(); + typedef void f(); + template void g() { T t; } + template void g(); 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 +int g(T t, U... u) +{ + return t + g(u...); +} + +template +int f1(T... t) +{ + return [t...] { + return g(t...); + }(); +} + +template +int f2(T... t) +{ + return [&t...] { + return g(t...); + }(); +} + +template +int f3(T... t) +{ + return [=] { + return g(t...); + }(); +} + +template +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); +} -- cgit v1.1