Re: C++ PATCH to add capture initializers to -std=c++1y
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
C++ PATCH to add capture initializers to -std=c++1y
At the Bristol C++ meeting we voted to accept generalized lambda capture initializers (e.g. [x = 42, y = std::move(y)]{ ... }), which were part of the initial implementation of lambdas in GCC, so initial support for C++1y is just a matter of checking cxx_dialect to avoid the pedwarn. The only thing missing from our implementation is support for list-initialization as well as = initialization; I'll add that soon. Tested x86_64-pc-linux-gnu, applying to trunk. commit a920644105779dceffd5912822b10b331457a227 Author: Jason Merrill ja...@redhat.com Date: Mon Apr 22 12:56:01 2013 -0400 N3648 * parser.c (cp_parser_lambda_introducer): Make lambda capture init pedwarn unconditional except in C++1y mode. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1893482..1fbc9bd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8518,9 +8518,10 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) { /* An explicit expression exists. */ cp_lexer_consume_token (parser-lexer); - pedwarn (input_location, OPT_Wpedantic, - ISO C++ does not allow initializers - in lambda expression capture lists); + 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); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C deleted file mode 100644 index 9b5ab79..000 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C +++ /dev/null @@ -1,27 +0,0 @@ -// Testcase for an extension to allow return type deduction when the lambda -// contains more than just a single return-statement. - -// { dg-options -std=c++0x } -// { dg-do run } - -bool b; -template class T -T f (T t) -{ - return [=] { -auto i = t+1; -if (b) - return i+1; -else - return i+1; - }(); -} - -int main() -{ - // Pointless, but well-formed. - [] { return 1; return 2; }(); - - if (f(1) != 3) -return 1; -} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C deleted file mode 100644 index 03c94e9..000 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C +++ /dev/null @@ -1,8 +0,0 @@ -// Test for the explicit initializer extension -// { dg-options -std=c++0x } - -int main() -{ - int j = [i = 2]{sizeof(i); return i;}(); - return (j != 2); -} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-deduce-mult.C b/gcc/testsuite/g++.dg/cpp1y/lambda-deduce-mult.C new file mode 100644 index 000..1181a80 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-deduce-mult.C @@ -0,0 +1,27 @@ +// Testcase for an extension to allow return type deduction when the lambda +// contains more than just a single return-statement. + +// { dg-options -std=c++1y } +// { dg-do run } + +bool b; +template class T +T f (T t) +{ + return [=] { +auto i = t+1; +if (b) + return i+1; +else + return i+1; + }(); +} + +int main() +{ + // Pointless, but well-formed. + [] { return 1; return 2; }(); + + if (f(1) != 3) +return 1; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init.C new file mode 100644 index 000..a443642 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init.C @@ -0,0 +1,8 @@ +// Test for the explicit initializer extension of C++1y +// { dg-options -std=c++1y } + +int main() +{ + int j = [i = 2]{sizeof(i); return i;}(); + return (j != 2); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init1.C new file mode 100644 index 000..6411fca --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init1.C @@ -0,0 +1,13 @@ +// N3648: capture init +// { dg-options -std=c++1y -w } +// { dg-do run } + +int main() +{ + int x = 41; + auto r = [x = x+1]{ return x; }(); + if (r != 42) __builtin_abort(); + + static auto *p = r; + [x=r]{ if (x != p) __builtin_abort(); }(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init2.C new file mode 100644 index 000..068621d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init2.C @@ -0,0 +1,13 @@ +// N3648: redundancy and capture init +// { dg-options -std=c++1y -pedantic-errors } + +int main() +{ + int x = 42; + [=,x]{}; // { dg-error redundant } + [=,x]{}; + [,x]{}; // { dg-error redundant } + [,x]{}; + [=,x=24]{}; + [,r=x]{}; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init3.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init3.C new file mode 100644 index 000..9044be6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init3.C @@ -0,0 +1,11 @@ +// N3648: capture init at non-block scope +// { dg-options -std=c++1y -w } +// { dg-do run } + +int i = 42; +int j = [x=i]{ return x; }(); + +int