This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: C++ PATCH to add capture initializers to -std=c++1y
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 24 Apr 2013 09:37:25 -0400
- Subject: Re: C++ PATCH to add capture initializers to -std=c++1y
- References: <51758D3A dot 1080305 at redhat dot com>
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 <jason@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 <jason@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" }
+}