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
This commit is contained in:
Jason Merrill 2009-10-06 18:14:01 -04:00 committed by Jason Merrill
parent ebde32fd24
commit 37a7519a24
9 changed files with 103 additions and 8 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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, "%<]%>");

View File

@ -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. */

View File

@ -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);

View File

@ -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

View File

@ -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]{};
}

View File

@ -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);
}