aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2009-10-06 18:14:01 -0400
committerJason Merrill <jason@gcc.gnu.org>2009-10-06 18:14:01 -0400
commit37a7519a24389c6e724566944b654e0ad3654a79 (patch)
tree91a2cc25814e680725f6c140def08bac99194893
parentebde32fd2478df9909e07843451956ce89a02b46 (diff)
downloadgcc-37a7519a24389c6e724566944b654e0ad3654a79.zip
gcc-37a7519a24389c6e724566944b654e0ad3654a79.tar.gz
gcc-37a7519a24389c6e724566944b654e0ad3654a79.tar.bz2
Fix lookup of initialized captures in unevaluated context.
* cp-tree.h (DECL_NORMAL_CAPTURE_P): New. * name-lookup.c (qualify_lookup): Check it. * parser.c (cp_parser_lambda_introducer): Pass explicit_init_p to add_capture. * semantics.c (add_capture): Set DECL_NORMAL_CAPTURE_P on captures without explicit init. (add_default_capture): Pass explicit_init_p. Fix capture by copy of types with explicit copy constructor. * cp-tree.h (TARGET_EXPR_DIRECT_INIT_P): New. (DIRECT_INIT_EXPR_P): New. * typeck.c (convert_for_initialization): Just return if DIRECT_INIT_EXPR_P. * parser.c (cp_parser_lambda_introducer): Use TARGET_EXPR_DIRECT_INIT_P for normal captures. From-SVN: r152500
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/cp-tree.h20
-rw-r--r--gcc/cp/name-lookup.c5
-rw-r--r--gcc/cp/parser.c8
-rw-r--r--gcc/cp/semantics.c27
-rw-r--r--gcc/cp/typeck.c5
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-direct-init.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C8
9 files changed, 103 insertions, 8 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 03f26c9..bb800f1 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,22 @@
+2009-10-06 Jason Merrill <jason@redhat.com>
+
+ Fix lookup of initialized captures in unevaluated context.
+ * cp-tree.h (DECL_NORMAL_CAPTURE_P): New.
+ * name-lookup.c (qualify_lookup): Check it.
+ * parser.c (cp_parser_lambda_introducer): Pass explicit_init_p
+ to add_capture.
+ * semantics.c (add_capture): Set DECL_NORMAL_CAPTURE_P
+ on captures without explicit init.
+ (add_default_capture): Pass explicit_init_p.
+
+ Fix capture by copy of types with explicit copy constructor.
+ * cp-tree.h (TARGET_EXPR_DIRECT_INIT_P): New.
+ (DIRECT_INIT_EXPR_P): New.
+ * typeck.c (convert_for_initialization): Just return if
+ DIRECT_INIT_EXPR_P.
+ * semantics.c (build_lambda_object): Use
+ TARGET_EXPR_DIRECT_INIT_P for normal captures.
+
2009-10-05 Jason Merrill <jason@redhat.com>
* parser.c: Mark lambda_scope and lambda_count for PCH.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8a18575..4b273c1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -97,6 +97,7 @@ framework extensions, you must include this file before toplev.h, not after.
STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
+ TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -147,6 +148,7 @@ framework extensions, you must include this file before toplev.h, not after.
DECL_FIELD_IS_BASE (in FIELD_DECL)
7: DECL_DEAD_FOR_LOCAL (in VAR_DECL).
DECL_THUNK_P (in a member FUNCTION_DECL)
+ DECL_NORMAL_CAPTURE_P (in FIELD_DECL)
Usage of language-independent fields in a language-dependent manner:
@@ -3199,6 +3201,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECL_FIELD_IS_BASE(NODE) \
DECL_LANG_FLAG_6 (FIELD_DECL_CHECK (NODE))
+/* Nonzero for FIELD_DECL node means that this field is a simple (no
+ explicit initializer) lambda capture field, making it invisible to
+ name lookup in unevaluated contexts. */
+#define DECL_NORMAL_CAPTURE_P(NODE) \
+ DECL_LANG_FLAG_7 (FIELD_DECL_CHECK (NODE))
+
/* Nonzero if TYPE is an anonymous union or struct type. We have to use a
flag for this because "A union for which objects or pointers are
declared is not an anonymous union" [class.union]. */
@@ -3633,6 +3641,16 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define TARGET_EXPR_LIST_INIT_P(NODE) \
TREE_LANG_FLAG_1 (TARGET_EXPR_CHECK (NODE))
+/* True if this TARGET_EXPR expresses direct-initialization of an object
+ to be named later. */
+#define TARGET_EXPR_DIRECT_INIT_P(NODE) \
+ TREE_LANG_FLAG_2 (TARGET_EXPR_CHECK (NODE))
+
+/* True if EXPR expresses direct-initialization of a TYPE. */
+#define DIRECT_INIT_EXPR_P(TYPE,EXPR) \
+ (TREE_CODE (EXPR) == TARGET_EXPR && TREE_LANG_FLAG_2 (EXPR) \
+ && same_type_ignoring_top_level_qualifiers_p (TYPE, TREE_TYPE (EXPR)))
+
/* An enumeration of the kind of tags that C++ accepts. */
enum tag_types {
none_type = 0, /* Not a tag type. */
@@ -5041,7 +5059,7 @@ extern tree lambda_capture_field_type (tree);
extern tree lambda_return_type (tree);
extern tree lambda_function (tree);
extern void apply_lambda_return_type (tree, tree);
-extern tree add_capture (tree, tree, tree, bool);
+extern tree add_capture (tree, tree, tree, bool, bool);
extern tree add_default_capture (tree, tree, tree);
extern tree lambda_expr_this_capture (tree);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 459e739..6e31f8a 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3757,10 +3757,9 @@ qualify_lookup (tree val, int flags)
return true;
if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
return false;
- /* In unevaluated context, look past capture fields. */
- /* FIXME this will cause trouble with the initializer extension. */
+ /* In unevaluated context, look past normal capture fields. */
if (cp_unevaluated_operand && TREE_CODE (val) == FIELD_DECL
- && LAMBDA_TYPE_P (DECL_CONTEXT (val)))
+ && DECL_NORMAL_CAPTURE_P (val))
return false;
return true;
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8ab930c..44dceb2 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7125,6 +7125,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
tree capture_id;
tree capture_init_expr;
cp_id_kind idk = CP_ID_KIND_NONE;
+ bool explicit_init_p = false;
enum capture_kind_type
{
@@ -7151,7 +7152,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
add_capture (lambda_expr,
/*id=*/get_identifier ("__this"),
/*initializer=*/finish_this_expr(),
- /*by_reference_p=*/false);
+ /*by_reference_p=*/false,
+ explicit_init_p);
continue;
}
@@ -7190,6 +7192,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
capture_init_expr = cp_parser_assignment_expression (parser,
/*cast_p=*/true,
&idk);
+ explicit_init_p = true;
}
else
{
@@ -7231,7 +7234,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
add_capture (lambda_expr,
capture_id,
capture_init_expr,
- /*by_reference_p=*/capture_kind == BY_REFERENCE);
+ /*by_reference_p=*/capture_kind == BY_REFERENCE,
+ explicit_init_p);
}
cp_parser_require (parser, CPP_CLOSE_SQUARE, "%<]%>");
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 8199af0..391228b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5328,6 +5328,20 @@ build_lambda_object (tree lambda_expr)
do some magic to make it work here. */
if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
val = build_array_copy (val);
+ else if (DECL_NORMAL_CAPTURE_P (field)
+ && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE)
+ {
+ /* "the entities that are captured by copy are used to
+ direct-initialize each corresponding non-static data
+ member of the resulting closure object."
+
+ There's normally no way to express direct-initialization
+ from an element of a CONSTRUCTOR, so we build up a special
+ TARGET_EXPR to bypass the usual copy-initialization. */
+ val = force_rvalue (val);
+ if (TREE_CODE (val) == TARGET_EXPR)
+ TARGET_EXPR_DIRECT_INIT_P (val) = true;
+ }
CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val);
}
@@ -5545,7 +5559,8 @@ capture_decltype (tree decl)
and return it. */
tree
-add_capture (tree lambda, tree id, tree initializer, bool by_reference_p)
+add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
+ bool explicit_init_p)
{
tree type;
tree member;
@@ -5560,6 +5575,13 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p)
/* Make member variable. */
member = build_lang_decl (FIELD_DECL, id, type);
+ if (!explicit_init_p)
+ /* Normal captures are invisible to name lookup but uses are replaced
+ with references to the capture field; we implement this by only
+ really making them invisible in unevaluated context; see
+ qualify_lookup. For now, let's make explicitly initialized captures
+ always visible. */
+ DECL_NORMAL_CAPTURE_P (member) = true;
/* Add it to the appropriate closure class. */
finish_member_declaration (member);
@@ -5605,7 +5627,8 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
/*by_reference_p=*/
(!this_capture_p
&& (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
- == CPLD_REFERENCE)));
+ == CPLD_REFERENCE)),
+ /*explicit_init_p=*/false);
{
/* Have to get the old value of current_class_ref. */
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index b4d54fc4..79b0201 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6893,6 +6893,11 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
type = complete_type (type);
+ if (DIRECT_INIT_EXPR_P (type, rhs))
+ /* Don't try to do copy-initialization if we already have
+ direct-initialization. */
+ return rhs;
+
if (MAYBE_CLASS_TYPE_P (type))
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7d5ed50..dd18805 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-10-06 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/lambda/lambda-init.C: New.
+ * g++.dg/cpp0x/lambda/lambda-direct-init.C: New.
+
2009-10-06 Richard Guenther <rguenther@suse.de>
PR lto/41502
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-direct-init.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-direct-init.C
new file mode 100644
index 0000000..bbc2a1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-direct-init.C
@@ -0,0 +1,14 @@
+// Test that capture by copy uses direct-initialization.
+// { dg-options "-std=c++0x" }
+
+struct A
+{
+ A();
+ explicit A(const A&);
+};
+
+int main()
+{
+ A a;
+ [a]{};
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C
new file mode 100644
index 0000000..03c94e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C
@@ -0,0 +1,8 @@
+// Test for the explicit initializer extension
+// { dg-options "-std=c++0x" }
+
+int main()
+{
+ int j = [i = 2]{sizeof(i); return i;}();
+ return (j != 2);
+}