On 04/22/2013 03:19 PM, Jason Merrill wrote:
The only thing missing from our implementation is support for list-initialization as well as = initialization; I'll add that soon.
These patches add that and parenthesized initializers, and also conform to the proposal that init-captures be nameable in the closure object.
Tested x86_64-pc-linux-gnu, applying to trunk. Jason
commit 91c5b39225cda83fe8bdb299fb30b85702059b6b Author: Jason Merrill <ja...@redhat.com> Date: Tue Apr 23 23:28:50 2013 -0400 N3648: Allow braced and parenthesized initializers. * parser.c (cp_parser_lambda_introducer): Use cp_parser_initializer. * pt.c (tsubst) [DECLTYPE_TYPE]: Handle DECLTYPE_FOR_INIT_CAPTURE. * semantics.c (lambda_capture_field_type): Use do_auto_deduction. (add_capture): Collapse a parenthesized initializer into a single expression. * cp-tree.h (DECLTYPE_FOR_INIT_CAPTURE): New. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d96340a..6254c7d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -90,6 +90,7 @@ c-common.h, not after. LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR) DECL_FINAL_P (in FUNCTION_DECL) QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) + DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -97,6 +98,7 @@ c-common.h, not after. TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) FNDECL_USED_AUTO (in FUNCTION_DECL) + DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -3590,10 +3592,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (DECLTYPE_TYPE_CHECK (NODE))->type_common.string_flag /* These flags indicate that we want different semantics from normal - decltype: lambda capture just drops references, lambda proxies look - through implicit dereference. */ + decltype: lambda capture just drops references, init capture + uses auto semantics, lambda proxies look through implicit dereference. */ #define DECLTYPE_FOR_LAMBDA_CAPTURE(NODE) \ TREE_LANG_FLAG_0 (DECLTYPE_TYPE_CHECK (NODE)) +#define DECLTYPE_FOR_INIT_CAPTURE(NODE) \ + TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE)) #define DECLTYPE_FOR_LAMBDA_PROXY(NODE) \ TREE_LANG_FLAG_2 (DECLTYPE_TYPE_CHECK (NODE)) @@ -5780,7 +5784,7 @@ extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); extern tree build_lambda_object (tree); extern tree begin_lambda_type (tree); -extern tree lambda_capture_field_type (tree); +extern tree lambda_capture_field_type (tree, bool); extern tree lambda_return_type (tree); extern tree lambda_proxy_type (tree); extern tree lambda_function (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0456dd2..cb26292 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8548,17 +8548,18 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) } /* Find the initializer for this capture. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ) + || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN) + || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - /* An explicit expression exists. */ - cp_lexer_consume_token (parser->lexer); + bool direct, non_constant; + /* An explicit initializer exists. */ if (cxx_dialect < cxx1y) pedwarn (input_location, 0, "lambda capture initializers " "only available with -std=c++1y or -std=gnu++1y"); - capture_init_expr = cp_parser_assignment_expression (parser, - /*cast_p=*/true, - &idk); + capture_init_expr = cp_parser_initializer (parser, &direct, + &non_constant); explicit_init_p = true; } else diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5f4d7a2..36e839f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11825,7 +11825,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) --c_inhibit_evaluation_warnings; if (DECLTYPE_FOR_LAMBDA_CAPTURE (t)) - type = lambda_capture_field_type (type); + type = lambda_capture_field_type (type, + DECLTYPE_FOR_INIT_CAPTURE (t)); else if (DECLTYPE_FOR_LAMBDA_PROXY (t)) type = lambda_proxy_type (type); else diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d4f0f82..da66168 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9123,14 +9123,22 @@ lambda_function (tree lambda) The caller should add REFERENCE_TYPE for capture by reference. */ tree -lambda_capture_field_type (tree expr) +lambda_capture_field_type (tree expr, bool explicit_init_p) { - tree type = non_reference (unlowered_expr_type (expr)); + tree type; + if (explicit_init_p) + { + type = make_auto (); + type = do_auto_deduction (type, expr, type); + } + else + type = non_reference (unlowered_expr_type (expr)); if (!type || WILDCARD_TYPE_P (type)) { type = cxx_make_type (DECLTYPE_TYPE); DECLTYPE_TYPE_EXPR (type) = expr; DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true; + DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p; SET_TYPE_STRUCTURAL_EQUALITY (type); } return type; @@ -9396,7 +9404,10 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, char *buf; tree type, member, name; - type = lambda_capture_field_type (initializer); + if (TREE_CODE (initializer) == TREE_LIST) + initializer = build_x_compound_expr_from_list (initializer, ELK_INIT, + tf_warning_or_error); + type = lambda_capture_field_type (initializer, explicit_init_p); if (by_reference_p) { type = build_reference_type (type); diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init5.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init5.C new file mode 100644 index 0000000..edada40 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init5.C @@ -0,0 +1,11 @@ +// Test for paren and brace initializers +// { dg-options "-std=c++1y" } +// { dg-do run } + +#include <initializer_list> + +int main() +{ + if ([x(42)]{ return x; }() != 42) __builtin_abort(); + if ([x{1,2}]{ return x.begin()[0]; }() != 1) __builtin_abort(); +} commit 3dc4bbcecb08ba63614ccba90cb6f20ff993a724 Author: Jason Merrill <ja...@redhat.com> Date: Wed Apr 24 09:26:15 2013 -0400 N3648: init-captures are named. * semantics.c (add_capture): Don't prepend "__" to init-captures. (build_capture_proxy): Adjust. * error.c (dump_simple_decl): Check DECL_NORMAL_CAPTURE_P. diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 7a8c0bc..4681e84 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -934,7 +934,7 @@ dump_simple_decl (tree t, tree type, int flags) pp_string (cxx_pp, "..."); if (DECL_NAME (t)) { - if (DECL_CLASS_SCOPE_P (t) && LAMBDA_TYPE_P (DECL_CONTEXT (t))) + if (TREE_CODE (t) == FIELD_DECL && DECL_NORMAL_CAPTURE_P (t)) { pp_character (cxx_pp, '<'); pp_string (cxx_pp, IDENTIFIER_POINTER (DECL_NAME (t)) + 2); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index da66168..e4bb1ed 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9369,7 +9369,10 @@ build_capture_proxy (tree member) object = TREE_OPERAND (object, 0); /* Remove the __ inserted by add_capture. */ - name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); + if (DECL_NORMAL_CAPTURE_P (member)) + name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); + else + name = DECL_NAME (member); type = lambda_proxy_type (object); var = build_decl (input_location, VAR_DECL, name, type); @@ -9422,11 +9425,17 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, won't find the field with name lookup. We can't just leave the name unset because template instantiation uses the name to find instantiated fields. */ - buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3); - buf[1] = buf[0] = '_'; - memcpy (buf + 2, IDENTIFIER_POINTER (id), - IDENTIFIER_LENGTH (id) + 1); - name = get_identifier (buf); + if (!explicit_init_p) + { + buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3); + buf[1] = buf[0] = '_'; + memcpy (buf + 2, IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id) + 1); + name = get_identifier (buf); + } + else + /* But captures with explicit initializers are named. */ + name = id; /* If TREE_TYPE isn't set, we're still in the introducer, so check for duplicates. */ diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init6.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init6.C new file mode 100644 index 0000000..3ebf479 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init6.C @@ -0,0 +1,12 @@ +// Test that simple captures are not named in the closure type, but +// initialized captures are named. +// { dg-options "-std=c++1y" } + +int main() +{ + int i; + auto lam = [i,j=42]{}; + lam.j; + lam.j.foo; // { dg-error "::j" } + lam.i; // { dg-error "no member" } +}