* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152500
138bc75d-0d04-0410-961f-
82ee72b054a4
+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.
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)
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:
#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]. */
#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. */
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);
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;
}
tree capture_id;
tree capture_init_expr;
cp_id_kind idk = CP_ID_KIND_NONE;
+ bool explicit_init_p = false;
enum capture_kind_type
{
add_capture (lambda_expr,
/*id=*/get_identifier ("__this"),
/*initializer=*/finish_this_expr(),
- /*by_reference_p=*/false);
+ /*by_reference_p=*/false,
+ explicit_init_p);
continue;
}
capture_init_expr = cp_parser_assignment_expression (parser,
/*cast_p=*/true,
&idk);
+ explicit_init_p = true;
}
else
{
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, "%<]%>");
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);
}
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;
/* 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);
/*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. */
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);
+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
--- /dev/null
+// 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]{};
+}
--- /dev/null
+// Test for the explicit initializer extension
+// { dg-options "-std=c++0x" }
+
+int main()
+{
+ int j = [i = 2]{sizeof(i); return i;}();
+ return (j != 2);
+}