From 37a7519a24389c6e724566944b654e0ad3654a79 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 6 Oct 2009 18:14:01 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 19 +++++++++++++ gcc/cp/cp-tree.h | 20 +++++++++++++- gcc/cp/name-lookup.c | 5 ++-- gcc/cp/parser.c | 8 ++++-- gcc/cp/semantics.c | 27 +++++++++++++++++-- gcc/cp/typeck.c | 5 ++++ gcc/testsuite/ChangeLog | 5 ++++ .../g++.dg/cpp0x/lambda/lambda-direct-init.C | 14 ++++++++++ .../g++.dg/cpp0x/lambda/lambda-init.C | 8 ++++++ 9 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-direct-init.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 03f26c9cc3b6..bb800f1b27c0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2009-10-06 Jason Merrill + + 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 * 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 8a185759912d..4b273c1221aa 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 459e7390805f..6e31f8a058a2 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 8ab930c7c81b..44dceb21f745 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 8199af0e6938..391228b02a63 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 b4d54fc40891..79b0201b77ad 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 7d5ed50f5d07..dd18805a6cc6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-10-06 Jason Merrill + + * g++.dg/cpp0x/lambda/lambda-init.C: New. + * g++.dg/cpp0x/lambda/lambda-direct-init.C: New. + 2009-10-06 Richard Guenther 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 000000000000..bbc2a1ca52d4 --- /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 000000000000..03c94e95981f --- /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); +} -- 2.43.5