From d5f4edddeb609ad93c7a69ad4575b082de8dc707 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 29 Sep 2009 23:01:30 -0400 Subject: [PATCH] merge in cxx0x-lambdas-branch@152308 From-SVN: r152318 --- MAINTAINERS | 1 + gcc/cp/ChangeLog | 91 +++ gcc/cp/class.c | 21 +- gcc/cp/cp-gimplify.c | 21 +- gcc/cp/cp-objcp-common.c | 2 + gcc/cp/cp-tree.def | 18 +- gcc/cp/cp-tree.h | 136 +++- gcc/cp/decl.c | 5 +- gcc/cp/error.c | 26 +- gcc/cp/mangle.c | 157 ++++- gcc/cp/method.c | 35 +- gcc/cp/name-lookup.c | 30 +- gcc/cp/parser.c | 603 +++++++++++++++++- gcc/cp/pt.c | 69 +- gcc/cp/search.c | 2 + gcc/cp/semantics.c | 522 ++++++++++++++- gcc/cp/tree.c | 31 + gcc/cp/typeck.c | 29 + gcc/cp/typeck2.c | 6 + gcc/testsuite/ChangeLog | 43 ++ .../g++.dg/cpp0x/lambda/lambda-array.C | 20 + .../lambda/lambda-capture-const-ref-neg.C | 14 + .../cpp0x/lambda/lambda-capture-const-ref.C | 15 + .../g++.dg/cpp0x/lambda/lambda-const-neg.C | 19 + .../g++.dg/cpp0x/lambda/lambda-const.C | 20 + .../cpp0x/lambda/lambda-copy-default-neg.C | 13 + .../g++.dg/cpp0x/lambda/lambda-copy-default.C | 14 + .../g++.dg/cpp0x/lambda/lambda-copy-neg.C | 13 + .../g++.dg/cpp0x/lambda/lambda-copy.C | 14 + .../g++.dg/cpp0x/lambda/lambda-ctor-neg.C | 25 + .../g++.dg/cpp0x/lambda/lambda-ctors.C | 18 + .../cpp0x/lambda/lambda-deduce-ext-neg.C | 24 + .../cpp0x/lambda/lambda-deduce-ext-neg2.C | 22 + .../g++.dg/cpp0x/lambda/lambda-deduce-ext.C | 27 + .../g++.dg/cpp0x/lambda/lambda-deduce-neg.C | 10 + .../g++.dg/cpp0x/lambda/lambda-deduce.C | 29 + .../g++.dg/cpp0x/lambda/lambda-defarg.C | 6 + gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C | 35 + .../g++.dg/cpp0x/lambda/lambda-errloc.C | 18 + .../g++.dg/cpp0x/lambda/lambda-field-names.C | 21 + .../g++.dg/cpp0x/lambda/lambda-in-class-neg.C | 35 + .../g++.dg/cpp0x/lambda/lambda-in-class.C | 36 ++ .../g++.dg/cpp0x/lambda/lambda-lookup-neg.C | 7 + .../g++.dg/cpp0x/lambda/lambda-mangle.C | 102 +++ .../g++.dg/cpp0x/lambda/lambda-mixed.C | 13 + .../g++.dg/cpp0x/lambda/lambda-mutable.C | 16 + .../g++.dg/cpp0x/lambda/lambda-nested.C | 52 ++ .../g++.dg/cpp0x/lambda/lambda-non-const.C | 19 + .../g++.dg/cpp0x/lambda/lambda-nop.C | 19 + .../g++.dg/cpp0x/lambda/lambda-ns-scope.C | 18 + .../g++.dg/cpp0x/lambda/lambda-pass.C | 27 + .../g++.dg/cpp0x/lambda/lambda-recursive.C | 21 + .../g++.dg/cpp0x/lambda/lambda-ref-default.C | 15 + .../g++.dg/cpp0x/lambda/lambda-ref.C | 15 + .../g++.dg/cpp0x/lambda/lambda-std-function.C | 22 + .../g++.dg/cpp0x/lambda/lambda-template.C | 41 ++ .../g++.dg/cpp0x/lambda/lambda-this.C | 13 + .../g++.dg/cpp0x/lambda/lambda-type.C | 74 +++ .../g++.dg/cpp0x/lambda/lambda-use.C | 12 + gcc/testsuite/lib/prune.exp | 2 +- include/ChangeLog.lambda | 6 + include/demangle.h | 14 + libiberty/ChangeLog | 11 + libiberty/Makefile.in | 6 +- libiberty/cp-demangle.c | 299 +++++++-- libiberty/testsuite/demangle-expected | 26 +- 66 files changed, 3004 insertions(+), 142 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-array.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctor-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctors.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-field-names.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-lookup-neg.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mixed.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nop.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ns-scope.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-pass.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-recursive.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref-default.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-std-function.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-type.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-use.C create mode 100644 include/ChangeLog.lambda diff --git a/MAINTAINERS b/MAINTAINERS index 7ed6d56d863..483ca638e6c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -328,6 +328,7 @@ Chris Fairles cfairles@gcc.gnu.org Li Feng nemokingdom@gmail.com Thomas Fitzsimmons fitzsim@redhat.com Brian Ford ford@vss.fsi.com +John Freeman jfreeman08@gmail.com Nathan Froyd froydnj@codesourcery.com Chao-ying Fu fu@mips.com Gary Funck gary@intrepid.com diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ff2d352d5eb..44c196deb4e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,94 @@ +2009-09-29 John Freeman + Jason Merrill + + Add support for lambda-expressions as per N2927. + * cp-tree.def (VEC_INIT_EXPR, LAMBDA_EXPR): New. + * cp-tree.h (LAMBDA_TYPE_P, LAMBDA_FUNCTION_P): New. + (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE): New. + (LAMBDA_EXPR_DEFAULT_CAPTURE_LIST): New. + (LAMBDA_EXPR_THIS_CAPTURE, LAMBDA_EXPR_CAPTURES_THIS_P): New. + (LAMBDA_EXPR_MUTABLE_P, LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P): New. + (LAMBDA_EXPR_RETURN_TYPE, LAMBDA_EXPR_LOCATION): New. + (LAMBDA_EXPR_EXTRA_SCOPE, LAMBDA_EXPR_DISCRIMINATOR): New. + (struct tree_lambda_expr): New. + (union lang_tree_node): Add lambda_expression. + (struct lang_type_class): Add lazy_move_ctor flag, lambda_expr field. + (CLASSTYPE_LAZY_MOVE_CTOR, CLASSTYPE_LAMBDA_EXPR): New. + (LAMBDA_TYPE_EXTRA_SCOPE, VEC_INIT_EXPR_SLOT): New. + (VEC_INIT_EXPR_INIT, DECLTYPE_FOR_LAMBDA_CAPTURE): New. + (DECLTYPE_FOR_LAMBDA_RETURN): New. + (enum special_function_kind): Add sfk_move_constructor. + (LAMBDANAME_PREFIX, LAMBDANAME_FORMAT, LAMBDANAME_P): New. + * parser.c (cp_parser_lambda_expression, cp_parser_lambda_introducer) + (cp_parser_lambda_declarator_opt, cp_parser_lambda_body): New. + (start_lambda_scope, record_lambda_scope, finish_lambda_scope): New. + (no_linkage_lambda_type_p): New. + (cp_parser_primary_expression): Recognize lambda expression. + (cp_parser_init_declarator): Note lambda scope. + (cp_parser_function_definition_after_declarator): Likewise. + (cp_parser_late_parsing_default_args): Likewise. + (cp_parser_skip_to_closing_parenthesis): Skip to end of lambda capture + lists, too. + (cp_parser_parameter_declaration): Don't defer lambda default args. + * semantics.c (finish_non_static_data_member, finish_id_expression): + Handle default capture for lambda expressions. + (finish_this_expr): Handle 'this' keyword inside of lambda expressions. + (outer_automatic_var_p): New. + (finish_decltype_type): Handle decltypes within lambda expressions. + (classtype_has_nothrow_assign_or_copy_p): Synthesized move constructor. + (build_lambda_expr, build_lambda_object, begin_lambda_type) + (lambda_return_type, lambda_capture_field_type, apply_lambda_return_type) + (capture_decltype, add_capture, add_default_capture) + (lambda_expr_this_capture): New. + * mangle.c (write_unnamed_type_name): New. Incomplete. + (write_closure_type_name): New. + (write_unqualified_name): Recognize unnamed, closure types. + (write_type): Do not write decltypes from lambda expressions. + (decl_mangling_context): New. + (write_name): Use it. Handle PARM_DECL scope. + (write_prefix): Likewise. Handle VAR_DECL/FIELD_DECL scope. + (write_compact_number): Factor out from... + (write_expression, write_template_param): ...here. + (discriminator_for_local_entity): Recognize lambdas. + (write_local_name): Handle PARM_DECL scope. + * typeck.c (structural_comptypes): Compare decltypes from lambda + expressions. + (check_return_expr): Deduce lambda return type from multiple return + statements. + * class.c (add_implicitly_declared_members): Add lazy move constructor + for lambda types. + (check_bases_and_members): Delete default constructor and assignment + operator for lambda types. + (maybe_note_name_used_in_class): Do not confuse lambda expression with + defining a class. + * decl.c (reshape_init_r): Array copy. + (grokfndecl): Synthesized move constructor. + (cp_tree_node_structure): Lambda expression. + * method.c (use_thunk): Synthesized move constructor. + (do_build_copy_constructor): Likewise. + (locate_copy): Likewise. + (implicitly_declare_fn): Likewise. + * cp-objcp-common.c (cp_tree_size): Handle LAMBDA_EXPR. + * error.c (dump_aggr_type): Recognize lambda type. + (dump_function_decl): Recognize lambda function. + (function_category): Likewise. + (dump_function_name): Hide lambda name. + * tree.c (build_array_copy, move): New. + (special_function_p): Synthesized move constructor. + (no_linkage_check): Handle lambdas. + * search.c (lookup_fnfields_1): Synthesized move constructor. + * cp-gimplify.c (cp_gimplify_init_expr, cp_gimplify_expr): + Handle VEC_INIT_EXPR. + * typeck2.c (digest_init_r): Array copy. + * pt.c (get_template_info): Don't touch typedefs. + (instantiate_decl): Don't resubstitute artificial decls. + (tsubst_decl, tsubst, tsubst_copy_and_build): Handle lambdas. + (lookup_template_class): Don't fall back on name lookup. + * name-lookup.c (make_lambda_name): New. + (pushdecl_class_level): Handle default capture for lambda expressions. + (qualify_lookup): Handle decltypes within lambda expressions. + (pushtag): Handle ts_within_enclosing_non_class in function scope. + 2009-09-28 Janis Johnson * mangle.c (write_builtin_type): Support decimal float types. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 9938a3d84d1..d29d6615f33 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2677,6 +2677,10 @@ add_implicitly_declared_members (tree t, CLASSTYPE_LAZY_COPY_CTOR (t) = 1; } + /* Currently only lambdas get a lazy move ctor. */ + if (LAMBDA_TYPE_P (t)) + CLASSTYPE_LAZY_MOVE_CTOR (t) = 1; + /* If there is no assignment operator, one will be created if and when it is needed. For now, just record whether or not the type of the parameter to the assignment operator will be a const or @@ -4449,6 +4453,20 @@ check_bases_and_members (tree t) cant_have_const_ctor, no_const_asn_ref); + if (LAMBDA_TYPE_P (t)) + { + /* "The closure type associated with a lambda-expression has a deleted + default constructor and a deleted copy assignment operator." */ + TYPE_NEEDS_CONSTRUCTING (t) = 1; + TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0; + CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 0; + TYPE_HAS_ASSIGN_REF (t) = 0; + CLASSTYPE_LAZY_ASSIGNMENT_OP (t) = 0; + + /* "This class type is not an aggregate." */ + CLASSTYPE_NON_AGGREGATE (t) = 1; + } + /* Create the in-charge and not-in-charge variants of constructors and destructors. */ clone_constructors_and_destructors (t); @@ -6601,7 +6619,8 @@ maybe_note_name_used_in_class (tree name, tree decl) /* If we're not defining a class, there's nothing to do. */ if (!(innermost_scope_kind() == sk_class - && TYPE_BEING_DEFINED (current_class_type))) + && TYPE_BEING_DEFINED (current_class_type) + && !LAMBDA_TYPE_P (current_class_type))) return; /* If there's already a binding for this NAME, then we don't have diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 52c12ebc187..017c8a98e45 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -452,10 +452,14 @@ cp_gimplify_init_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) Should we add a target parm to gimplify_expr instead? No, as in this case we want to replace the INIT_EXPR. */ - if (TREE_CODE (sub) == AGGR_INIT_EXPR) + if (TREE_CODE (sub) == AGGR_INIT_EXPR + || TREE_CODE (sub) == VEC_INIT_EXPR) { gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); - AGGR_INIT_EXPR_SLOT (sub) = to; + if (TREE_CODE (sub) == AGGR_INIT_EXPR) + AGGR_INIT_EXPR_SLOT (sub) = to; + else + VEC_INIT_EXPR_SLOT (sub) = to; *expr_p = from; /* The initialization is now a side-effect, so the container can @@ -523,6 +527,19 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) ret = GS_OK; break; + case VEC_INIT_EXPR: + { + location_t loc = input_location; + gcc_assert (EXPR_HAS_LOCATION (*expr_p)); + input_location = EXPR_LOCATION (*expr_p); + *expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE, + VEC_INIT_EXPR_INIT (*expr_p), false, 1, + tf_warning_or_error); + ret = GS_OK; + input_location = loc; + } + break; + case THROW_EXPR: /* FIXME communicate throw type to back end, probably by moving THROW_EXPR into ../tree.def. */ diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 32e5530f243..da6f8291ba4 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -138,6 +138,8 @@ cp_tree_size (enum tree_code code) case TRAIT_EXPR: return sizeof (struct tree_trait_expr); + case LAMBDA_EXPR: return sizeof (struct tree_lambda_expr); + default: gcc_unreachable (); } diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index a43fa825307..4df01a8e205 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -81,6 +81,11 @@ DEFTREECODE (TYPE_EXPR, "type_expr", tcc_expression, 1) the remaining operands are the arguments to the initialization function. */ DEFTREECODE (AGGR_INIT_EXPR, "aggr_init_expr", tcc_vl_exp, 3) +/* Initialization of an array from another array, expressed at a high level + so that it works with TARGET_EXPR. Operand 0 is the target, operand 1 + is the initializer. */ +DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", tcc_expression, 2) + /* A throw expression. operand 0 is the expression, if there was one, else it is NULL_TREE. */ DEFTREECODE (THROW_EXPR, "throw_expr", tcc_expression, 1) @@ -416,11 +421,22 @@ DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0) /* Represents a trait expression during template expansion. */ DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0) +/* A lambda expression. This is a C++0x extension. + LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be + none. + LAMBDA_EXPR_CAPTURE_LIST holds the capture-list, including `this'. + LAMBDA_EXPR_THIS_CAPTURE goes straight to the capture of `this', if it exists. + LAMBDA_EXPR_MUTABLE_P signals whether this lambda was declared mutable. + LAMBDA_EXPR_RETURN_TYPE holds the return type, if it was specified. */ +DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0) + /* The declared type of an expression. This is a C++0x extension. DECLTYPE_TYPE_EXPR is the expression whose type we are computing. DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P states whether the expression was parsed as an id-expression or a member access - expression. When false, it was parsed as a full expression. */ + expression. When false, it was parsed as a full expression. + DECLTYPE_FOR_LAMBDA_CAPTURE is set if we want lambda capture semantics. + DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction. */ DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0) /* diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c089bb75f27..0487a9f0aac 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -77,6 +77,8 @@ framework extensions, you must include this file before toplev.h, not after. TYPE_REF_IS_RVALUE (in REFERENCE_TYPE) ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute) CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR) + LAMBDA_EXPR_CAPTURES_THIS_P (in LAMBDA_EXPR) + DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -87,11 +89,14 @@ framework extensions, you must include this file before toplev.h, not after. TYPENAME_IS_CLASS_P (in TYPENAME_TYPE) STMT_IS_FULL_EXPR_P (in _STMT) TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR) + LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR) + DECLTYPE_FOR_LAMBDA_RETURN (in DECLTYPE_TYPE) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST) TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) + LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -517,6 +522,81 @@ struct GTY (()) tree_trait_expr { enum cp_trait_kind kind; }; +/* Based off of TYPE_ANONYMOUS_P. */ +#define LAMBDA_TYPE_P(NODE) \ + (CLASS_TYPE_P (NODE) && LAMBDANAME_P (TYPE_LINKAGE_IDENTIFIER (NODE))) + +/* Test if FUNCTION_DECL is a lambda function. */ +#define LAMBDA_FUNCTION_P(FNDECL) \ + (DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \ + && LAMBDA_TYPE_P (CP_DECL_CONTEXT (FNDECL))) + +enum cp_lambda_default_capture_mode_type { + CPLD_NONE, + CPLD_COPY, + CPLD_REFERENCE +}; + +/* The method of default capture, if any. */ +#define LAMBDA_EXPR_DEFAULT_CAPTURE_MODE(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->default_capture_mode) + +/* The capture-list, including `this'. Each capture is stored as a FIELD_DECL + * so that the name, type, and field are all together, whether or not it has + * been added to the lambda's class type. + TREE_LIST: + TREE_PURPOSE: The FIELD_DECL for this capture. + TREE_VALUE: The initializer. This is part of a GNU extension. */ +#define LAMBDA_EXPR_CAPTURE_LIST(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->capture_list) + +/* The node in the capture-list that holds the 'this' capture. */ +#define LAMBDA_EXPR_THIS_CAPTURE(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture) + +/* Predicate tracking whether `this' is in the effective capture set. */ +#define LAMBDA_EXPR_CAPTURES_THIS_P(NODE) \ + LAMBDA_EXPR_THIS_CAPTURE(NODE) + +/* Predicate tracking whether the lambda was declared 'mutable'. */ +#define LAMBDA_EXPR_MUTABLE_P(NODE) \ + TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE)) + +/* True iff we should try to deduce the lambda return type from any return + statement. */ +#define LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P(NODE) \ + TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) + +/* The return type in the expression. + * NULL_TREE indicates that none was specified. */ +#define LAMBDA_EXPR_RETURN_TYPE(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->return_type) + +/* The source location of the lambda. */ +#define LAMBDA_EXPR_LOCATION(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->locus) + +/* The mangling scope for the lambda: FUNCTION_DECL, PARM_DECL, VAR_DECL, + FIELD_DECL or NULL_TREE. If this is NULL_TREE, we have no linkage. */ +#define LAMBDA_EXPR_EXTRA_SCOPE(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_scope) + +/* If EXTRA_SCOPE, this is the number of the lambda within that scope. */ +#define LAMBDA_EXPR_DISCRIMINATOR(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator) + +struct GTY (()) tree_lambda_expr +{ + struct tree_common common; + location_t locus; + enum cp_lambda_default_capture_mode_type default_capture_mode; + tree capture_list; + tree this_capture; + tree return_type; + tree extra_scope; + int discriminator; +}; + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -530,6 +610,7 @@ enum cp_tree_node_structure_enum { TS_CP_STATIC_ASSERT, TS_CP_ARGUMENT_PACK_SELECT, TS_CP_TRAIT_EXPR, + TS_CP_LAMBDA_EXPR, LAST_TS_CP_ENUM }; @@ -550,6 +631,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), argument_pack_select; struct tree_trait_expr GTY ((tag ("TS_CP_TRAIT_EXPR"))) trait_expression; + struct tree_lambda_expr GTY ((tag ("TS_CP_LAMBDA_EXPR"))) + lambda_expression; }; @@ -1127,6 +1210,7 @@ struct GTY(()) lang_type_class { unsigned has_complex_dflt : 1; unsigned has_list_ctor : 1; unsigned non_std_layout : 1; + unsigned lazy_move_ctor : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -1135,7 +1219,7 @@ struct GTY(()) lang_type_class { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 9; + unsigned dummy : 8; tree primary_base; VEC(tree_pair_s,gc) *vcall_indices; @@ -1159,6 +1243,8 @@ struct GTY(()) lang_type_class { to resort it if pointers get rearranged. */ struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) sorted_fields; + /* FIXME reuse another field? */ + tree lambda_expr; }; struct GTY(()) lang_type_ptrmem { @@ -1221,6 +1307,11 @@ struct GTY(()) lang_type { #define CLASSTYPE_LAZY_COPY_CTOR(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->lazy_copy_ctor) +/* Nonzero means that NODE (a class type) has a move constructor -- + but that it has not yet been declared. */ +#define CLASSTYPE_LAZY_MOVE_CTOR(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->lazy_move_ctor) + /* Nonzero means that NODE (a class type) has an assignment operator -- but that it has not yet been declared. */ #define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \ @@ -1426,6 +1517,13 @@ struct GTY(()) lang_type { #define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->befriending_classes) +/* The associated LAMBDA_EXPR that made this class. */ +#define CLASSTYPE_LAMBDA_EXPR(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->lambda_expr) +/* The extra mangling scope for this closure type. */ +#define LAMBDA_TYPE_EXTRA_SCOPE(NODE) \ + (LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (NODE))) + /* Say whether this node was declared as a "class" or a "struct". */ #define CLASSTYPE_DECLARED_CLASS(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->declared_class) @@ -2625,6 +2723,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) for ((arg) = first_aggr_init_expr_arg ((call), &(iter)); (arg); \ (arg) = next_aggr_init_expr_arg (&(iter))) +/* VEC_INIT_EXPR accessors. */ +#define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (NODE, 0) +#define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (NODE, 1) + /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a TEMPLATE_DECL. This macro determines whether or not a given class type is really a template type, as opposed to an instantiation or @@ -3058,6 +3160,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P(NODE) \ (DECLTYPE_TYPE_CHECK (NODE))->type.string_flag +/* These flags indicate that we want different semantics from normal + decltype: lambda capture just drops references, lambda return also does + type decay. */ +#define DECLTYPE_FOR_LAMBDA_CAPTURE(NODE) \ + TREE_LANG_FLAG_0 (DECLTYPE_TYPE_CHECK (NODE)) +#define DECLTYPE_FOR_LAMBDA_RETURN(NODE) \ + TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE)) + /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was specified in its declaration. This can also be set for an erroneously declared PARM_DECL. */ @@ -3570,6 +3680,7 @@ typedef enum special_function_kind { special_function_p. */ sfk_constructor, /* A constructor. */ sfk_copy_constructor, /* A copy constructor. */ + sfk_move_constructor, /* A move constructor. */ sfk_assignment_operator, /* An assignment operator. */ sfk_destructor, /* A destructor. */ sfk_complete_destructor, /* A destructor for complete objects. */ @@ -3778,6 +3889,13 @@ extern GTY(()) VEC(tree,gc) *local_classes; #define VTABLE_DELTA_NAME "__delta" #define VTABLE_PFN_NAME "__pfn" +#define LAMBDANAME_PREFIX "__lambda" +#define LAMBDANAME_FORMAT LAMBDANAME_PREFIX "%d" +#define LAMBDANAME_P(ID_NODE) \ + (!strncmp (IDENTIFIER_POINTER (ID_NODE), \ + LAMBDANAME_PREFIX, \ + sizeof (LAMBDANAME_PREFIX) - 1)) + #if !defined(NO_DOLLAR_IN_LABEL) || !defined(NO_DOT_IN_LABEL) #define VTABLE_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == 'v' \ @@ -4377,6 +4495,7 @@ enum cp_tree_node_structure_enum cp_tree_node_structure extern void finish_scope (void); extern void push_switch (tree); extern void pop_switch (void); +extern tree make_lambda_name (void); extern int decls_match (tree, tree); extern tree duplicate_decls (tree, tree, bool); extern tree declare_local_label (tree); @@ -4897,6 +5016,16 @@ extern void finish_static_assert (tree, tree, location_t, extern tree describable_type (tree); extern tree finish_decltype_type (tree, bool); 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_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_default_capture (tree, tree, tree); +extern tree lambda_expr_this_capture (tree); /* in tree.c */ void cp_free_lang_data (tree t); @@ -4934,6 +5063,7 @@ extern tree build_aggr_init_expr (tree, tree); extern tree get_target_expr (tree); extern tree build_cplus_array_type (tree, tree); extern tree build_array_of_n_type (tree, int); +extern tree build_array_copy (tree); extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); extern tree build_qualified_name (tree, tree, tree, bool); @@ -4965,6 +5095,7 @@ extern const struct attribute_spec cxx_attribute_table[]; extern tree make_ptrmem_cst (tree, tree); extern tree cp_build_type_attribute_variant (tree, tree); extern tree cp_build_reference_type (tree, bool); +extern tree move (tree); extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t); #define cp_build_qualified_type(TYPE, QUALS) \ cp_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) @@ -5157,6 +5288,9 @@ extern tree cxx_omp_clause_dtor (tree, tree); extern void cxx_omp_finish_clause (tree); extern bool cxx_omp_privatize_by_reference (const_tree); +/* in parser.c */ +extern bool no_linkage_lambda_type_p (tree); + /* -- end of C++ */ #endif /* ! GCC_CP_TREE_H */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c720f6c33a3..80238c18881 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4921,7 +4921,8 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p) looking through the outermost braces; A a2 = { a1 }; is not a valid aggregate initialization. */ && !first_initializer_p - && can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL)) + && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (init)) + || can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL))) { d->cur++; return init; @@ -6622,6 +6623,7 @@ grokfndecl (tree ctype, { case sfk_constructor: case sfk_copy_constructor: + case sfk_move_constructor: DECL_CONSTRUCTOR_P (decl) = 1; break; case sfk_destructor: @@ -12687,6 +12689,7 @@ cp_tree_node_structure (union lang_tree_node * t) case STATIC_ASSERT: return TS_CP_STATIC_ASSERT; case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; + case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; default: return TS_CP_GENERIC; } } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 5d38e026454..b50704a3ae4 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -597,6 +597,15 @@ dump_aggr_type (tree t, int flags) else pp_printf (pp_base (cxx_pp), M_(""), variety); } + else if (LAMBDANAME_P (name)) + { + /* A lambda's "type" is essentially its signature. */ + pp_string (cxx_pp, M_("'); + } else pp_cxx_tree_identifier (cxx_pp, name); if (tmplate) @@ -1224,6 +1233,14 @@ dump_function_decl (tree t, int flags) tree exceptions; VEC(tree,gc) *typenames = NULL; + if (LAMBDA_FUNCTION_P (t)) + { + /* A lambda's signature is essentially its "type", so defer. */ + gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); + dump_type (DECL_CONTEXT (t), flags); + return; + } + flags &= ~TFF_UNQUALIFIED_NAME; if (TREE_CODE (t) == TEMPLATE_DECL) t = DECL_TEMPLATE_RESULT (t); @@ -1401,7 +1418,12 @@ dump_function_name (tree t, int flags) /* Don't let the user see __comp_ctor et al. */ if (DECL_CONSTRUCTOR_P (t) || DECL_DESTRUCTOR_P (t)) - name = constructor_name (DECL_CONTEXT (t)); + { + if (LAMBDA_TYPE_P (DECL_CONTEXT (t))) + name = get_identifier (""); + else + name = constructor_name (DECL_CONTEXT (t)); + } if (DECL_DESTRUCTOR_P (t)) { @@ -2676,6 +2698,8 @@ function_category (tree fn) return _("In constructor %qs"); else if (DECL_DESTRUCTOR_P (fn)) return _("In destructor %qs"); + else if (LAMBDA_FUNCTION_P (fn)) + return _("In lambda function"); else return _("In member function %qs"); } diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index bcaf5b0f940..1e08465195c 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -182,10 +182,13 @@ static void write_template_prefix (const tree); static void write_unqualified_name (const tree); static void write_conversion_operator_name (const tree); static void write_source_name (tree); +static void write_unnamed_type_name (const tree); +static void write_closure_type_name (const tree); static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *, const unsigned int); static void write_number (unsigned HOST_WIDE_INT, const int, const unsigned int); +static void write_compact_number (int num); static void write_integer_cst (const tree); static void write_real_cst (const tree); static void write_identifier (const char *); @@ -211,7 +214,7 @@ static void write_substitution (const int); static int discriminator_for_local_entity (tree); static int discriminator_for_string_literal (tree, tree); static void write_discriminator (const int); -static void write_local_name (const tree, const tree, const tree); +static void write_local_name (tree, const tree, const tree); static void dump_substitution_candidates (void); static tree mangle_decl_string (const tree); @@ -744,6 +747,22 @@ needs_fake_anon (const_tree decl) && TREE_CODE (decl) == FUNCTION_DECL); } +/* Lambdas can have a bit more context for mangling, specifically VAR_DECL + or PARM_DECL context, which doesn't belong in DECL_CONTEXT. */ + +static tree +decl_mangling_context (tree decl) +{ + if (TREE_CODE (decl) == TYPE_DECL + && LAMBDA_TYPE_P (TREE_TYPE (decl))) + { + tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)); + if (extra) + return extra; + } + return CP_DECL_CONTEXT (decl); +} + /* ::= ::= ::= @@ -767,10 +786,9 @@ write_name (tree decl, const int ignore_local_scope) /* In case this is a typedef, fish out the corresponding TYPE_DECL for the main variant. */ decl = TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - context = CP_TYPE_CONTEXT (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); } - else - context = CP_DECL_CONTEXT (decl); + + context = decl_mangling_context (decl); gcc_assert (context != NULL_TREE); @@ -822,7 +840,8 @@ write_name (tree decl, const int ignore_local_scope) if (TYPE_P (context)) context = TYPE_NAME (context); /* Is this a function? */ - if (TREE_CODE (context) == FUNCTION_DECL) + if (TREE_CODE (context) == FUNCTION_DECL + || TREE_CODE (context) == PARM_DECL) { /* Yes, we have local scope. Use the production for the innermost function scope. */ @@ -831,7 +850,7 @@ write_name (tree decl, const int ignore_local_scope) } /* Up one scope level. */ local_entity = context; - context = CP_DECL_CONTEXT (context); + context = decl_mangling_context (context); } /* No local scope found? Fall through to . */ @@ -955,23 +974,24 @@ write_prefix (const tree node) /* Non-NULL if NODE represents a template-id. */ tree template_info = NULL; - MANGLE_TRACE_TREE ("prefix", node); - if (node == NULL || node == global_namespace) return; + MANGLE_TRACE_TREE ("prefix", node); + if (find_substitution (node)) return; if (DECL_P (node)) { - /* If this is a function decl, that means we've hit function + /* If this is a function or parm decl, that means we've hit function scope, so this prefix must be for a local name. In this case, we're under the production, which encodes the enclosing function scope elsewhere. So don't continue here. */ - if (TREE_CODE (node) == FUNCTION_DECL) + if (TREE_CODE (node) == FUNCTION_DECL + || TREE_CODE (node) == PARM_DECL) return; decl = node; @@ -1016,8 +1036,15 @@ write_prefix (const tree node) else /* Not templated. */ { - write_prefix (CP_DECL_CONTEXT (decl)); + write_prefix (decl_mangling_context (decl)); write_unqualified_name (decl); + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FIELD_DECL) + { + /* := M */ + write_char ('M'); + return; + } } add_substitution (node); @@ -1107,6 +1134,7 @@ write_template_prefix (const tree node) ::= ::= ::= + ::= ::= ::= L */ @@ -1172,7 +1200,19 @@ write_unqualified_name (const tree decl) so there's no code to output one here. */ } else - write_source_name (DECL_NAME (decl)); + { + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + && TYPE_ANONYMOUS_P (type) + && !ANON_UNION_TYPE_P (type)) + write_unnamed_type_name (type); + else if (TREE_CODE (decl) == TYPE_DECL + && LAMBDA_TYPE_P (type)) + write_closure_type_name (type); + else + write_source_name (DECL_NAME (decl)); + } } /* Write the unqualified-name for a conversion operator to TYPE. */ @@ -1202,6 +1242,44 @@ write_source_name (tree identifier) write_identifier (IDENTIFIER_POINTER (identifier)); } +/* Encode 0 as _, and 1+ as n-1_. */ + +static void +write_compact_number (int num) +{ + if (num > 0) + write_unsigned_number (num - 1); + write_char ('_'); +} + +static void +write_unnamed_type_name (const tree type __attribute__ ((__unused__))) +{ + MANGLE_TRACE_TREE ("unnamed-type-name", type); + + write_string ("Ut"); + /* TODO: Implement discriminators for unnamed-types. */ + write_char ('_'); +} + +/* ::= Ul E [ ] _ + ::= + # Parameter types or "v" if the lambda has no parameters */ + +static void +write_closure_type_name (const tree type) +{ + tree fn = lambda_function (type); + tree lambda = CLASSTYPE_LAMBDA_EXPR (type); + tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); + + MANGLE_TRACE_TREE ("closure-type-name", type); + + write_string ("Ul"); + write_method_parms (parms, /*method_p=*/1, fn); + write_char ('E'); + write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); +} + /* Convert NUMBER to ascii using base BASE and generating at least MIN_DIGITS characters. BUFFER points to the _end_ of the buffer into which to store the characters. Returns the number of @@ -1479,6 +1557,11 @@ discriminator_for_local_entity (tree entity) /* Scan the list of local classes. */ entity = TREE_TYPE (entity); + + /* Lambdas and unnamed types have their own discriminators. */ + if (LAMBDA_TYPE_P (entity) || TYPE_ANONYMOUS_P (entity)) + return 0; + for (ix = 0; ; ix++) { tree type = VEC_index (tree, local_classes, ix); @@ -1523,23 +1606,49 @@ write_discriminator (const int discriminator) } /* Mangle the name of a function-scope entity. FUNCTION is the - FUNCTION_DECL for the enclosing function. ENTITY is the decl for - the entity itself. LOCAL_ENTITY is the entity that's directly - scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope - of ENTITY. + FUNCTION_DECL for the enclosing function, or a PARM_DECL for lambdas in + default argument scope. ENTITY is the decl for the entity itself. + LOCAL_ENTITY is the entity that's directly scoped in FUNCTION_DECL, + either ENTITY itself or an enclosing scope of ENTITY. := Z E [] - := Z E s [] */ + := Z E s [] + := Z Ed [ ] _ */ static void -write_local_name (const tree function, const tree local_entity, +write_local_name (tree function, const tree local_entity, const tree entity) { + tree parm = NULL_TREE; + MANGLE_TRACE_TREE ("local-name", entity); + if (TREE_CODE (function) == PARM_DECL) + { + parm = function; + function = DECL_CONTEXT (parm); + } + write_char ('Z'); write_encoding (function); write_char ('E'); + + /* For this purpose, parameters are numbered from right-to-left. */ + if (parm) + { + tree t; + int i = 0; + for (t = DECL_ARGUMENTS (function); t; t = TREE_CHAIN (t)) + { + if (t == parm) + i = 1; + else if (i) + ++i; + } + write_char ('d'); + write_compact_number (i - 1); + } + if (TREE_CODE (entity) == STRING_CST) { write_char ('s'); @@ -1718,6 +1827,10 @@ write_type (tree type) break; case DECLTYPE_TYPE: + /* These shouldn't make it into mangling. */ + gcc_assert (!DECLTYPE_FOR_LAMBDA_CAPTURE (type) + && !DECLTYPE_FOR_LAMBDA_RETURN (type)); + write_char ('D'); if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)) write_char ('t'); @@ -2236,9 +2349,7 @@ write_expression (tree expr) int index = DECL_PARM_INDEX (expr); gcc_assert (index >= 1); write_string ("fp"); - if (index > 1) - write_unsigned_number (index - 2); - write_char ('_'); + write_compact_number (index - 1); } else if (DECL_P (expr)) { @@ -2701,9 +2812,7 @@ write_template_param (const tree parm) write_char ('T'); /* NUMBER as it appears in the mangling is (-1)-indexed, with the earliest template param denoted by `_'. */ - if (parm_index > 0) - write_unsigned_number (parm_index - 1); - write_char ('_'); + write_compact_number (parm_index); } /* diff --git a/gcc/cp/method.c b/gcc/cp/method.c index b0df48938a8..e8b28d877d7 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -530,12 +530,13 @@ use_thunk (tree thunk_fndecl, bool emit_p) /* Code for synthesizing methods which have default semantics defined. */ -/* Generate code for default X(X&) constructor. */ +/* Generate code for default X(X&) or X(X&&) constructor. */ static void do_build_copy_constructor (tree fndecl) { tree parm = FUNCTION_FIRST_USER_PARM (fndecl); + bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl); parm = convert_from_reference (parm); @@ -555,6 +556,7 @@ do_build_copy_constructor (tree fndecl) int cvquals = cp_type_quals (TREE_TYPE (parm)); int i; tree binfo, base_binfo; + tree init; VEC(tree,gc) *vbases; /* Initialize all the base-classes with the parameter converted @@ -565,11 +567,12 @@ do_build_copy_constructor (tree fndecl) for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0; VEC_iterate (tree, vbases, i, binfo); i++) { + init = build_base_path (PLUS_EXPR, parm, binfo, 1); + if (move_p) + init = move (init); member_init_list = tree_cons (binfo, - build_tree_list (NULL_TREE, - build_base_path (PLUS_EXPR, parm, - binfo, 1)), + build_tree_list (NULL_TREE, init), member_init_list); } @@ -579,17 +582,17 @@ do_build_copy_constructor (tree fndecl) if (BINFO_VIRTUAL_P (base_binfo)) continue; + init = build_base_path (PLUS_EXPR, parm, base_binfo, 1); + if (move_p) + init = move (init); member_init_list = tree_cons (base_binfo, - build_tree_list (NULL_TREE, - build_base_path (PLUS_EXPR, parm, - base_binfo, 1)), + build_tree_list (NULL_TREE, init), member_init_list); } for (; fields; fields = TREE_CHAIN (fields)) { - tree init = parm; tree field = fields; tree expr_type; @@ -622,7 +625,9 @@ do_build_copy_constructor (tree fndecl) expr_type = cp_build_qualified_type (expr_type, quals); } - init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); + init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE); + if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE) + init = move (init); init = build_tree_list (NULL_TREE, init); member_init_list = tree_cons (field, init, member_init_list); @@ -936,6 +941,8 @@ locate_copy (tree type, void *client_) it now. */ if (CLASSTYPE_LAZY_COPY_CTOR (type)) lazily_declare_fn (sfk_copy_constructor, type); + if (CLASSTYPE_LAZY_MOVE_CTOR (type)) + lazily_declare_fn (sfk_move_constructor, type); fns = CLASSTYPE_CONSTRUCTORS (type); } else @@ -1036,6 +1043,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) case sfk_copy_constructor: case sfk_assignment_operator: + case sfk_move_constructor: { struct copy_data data; @@ -1057,7 +1065,9 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) } else rhs_parm_type = type; - rhs_parm_type = build_reference_type (rhs_parm_type); + rhs_parm_type + = cp_build_reference_type (rhs_parm_type, + kind == sfk_move_constructor); parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types); raises = synthesize_exception_spec (type, &locate_copy, &data); break; @@ -1072,7 +1082,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) fn_type = build_exception_variant (fn_type, raises); fn = build_lang_decl (FUNCTION_DECL, name, fn_type); DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type)); - if (kind == sfk_constructor || kind == sfk_copy_constructor) + if (kind == sfk_constructor || kind == sfk_copy_constructor + || kind == sfk_move_constructor) DECL_CONSTRUCTOR_P (fn) = 1; else if (kind == sfk_destructor) DECL_DESTRUCTOR_P (fn) = 1; @@ -1175,6 +1186,8 @@ lazily_declare_fn (special_function_kind sfk, tree type) CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0; else if (sfk == sfk_copy_constructor) CLASSTYPE_LAZY_COPY_CTOR (type) = 0; + else if (sfk == sfk_move_constructor) + CLASSTYPE_LAZY_MOVE_CTOR (type) = 0; else if (sfk == sfk_destructor) CLASSTYPE_LAZY_DESTRUCTOR (type) = 0; /* Create appropriate clones. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index d37cf44d2d8..459e7390805 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1834,6 +1834,23 @@ make_anon_name (void) return get_identifier (buf); } +/* This code is practically identical to that for creating + anonymous names, but is just used for lambdas instead. This is necessary + because anonymous names are recognized and cannot be passed to template + functions. */ +/* FIXME is this still necessary? */ + +static GTY(()) int lambda_cnt = 0; + +tree +make_lambda_name (void) +{ + char buf[32]; + + sprintf (buf, LAMBDANAME_FORMAT, lambda_cnt++); + return get_identifier (buf); +} + /* Return (from the stack of) the BINDING, if any, established at SCOPE. */ static inline cxx_binding * @@ -2637,6 +2654,11 @@ pushdecl_class_level (tree x) tree name; bool is_valid = true; + /* Do nothing if we're adding to an outer lambda closure type, + outer_binding will add it later if it's needed. */ + if (current_class_type != class_binding_level->this_entity) + return true; + timevar_push (TV_NAME_LOOKUP); /* Get the name of X. */ if (TREE_CODE (x) == OVERLOAD) @@ -3735,6 +3757,11 @@ 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. */ + if (cp_unevaluated_operand && TREE_CODE (val) == FIELD_DECL + && LAMBDA_TYPE_P (DECL_CONTEXT (val))) + return false; return true; } @@ -5114,7 +5141,8 @@ pushtag (tree name, tree type, tag_scope scope) { tree cs = current_scope (); - if (scope == ts_current) + if (scope == ts_current + || (cs && TREE_CODE (cs) == FUNCTION_DECL)) context = cs; else if (cs != NULL_TREE && TYPE_P (cs)) /* When declaring a friend class of a local class, we want diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 55effed939e..84cdef4b8d5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1626,6 +1626,14 @@ static tree cp_parser_constant_expression (cp_parser *, bool, bool *); static tree cp_parser_builtin_offsetof (cp_parser *); +static tree cp_parser_lambda_expression + (cp_parser *); +static void cp_parser_lambda_introducer + (cp_parser *, tree); +static void cp_parser_lambda_declarator_opt + (cp_parser *, tree); +static void cp_parser_lambda_body + (cp_parser *, tree); /* Statements [gram.stmt.stmt] */ @@ -2452,6 +2460,7 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser, { unsigned paren_depth = 0; unsigned brace_depth = 0; + unsigned square_depth = 0; if (recovering && !or_comma && cp_parser_uncommitted_to_tentative_parse_p (parser)) @@ -2468,6 +2477,15 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser, /* If we've run out of tokens, then there is no closing `)'. */ return 0; + /* This is good for lambda expression capture-lists. */ + case CPP_OPEN_SQUARE: + ++square_depth; + break; + case CPP_CLOSE_SQUARE: + if (!square_depth--) + return 0; + break; + case CPP_SEMICOLON: /* This matches the processing in skip_to_end_of_statement. */ if (!brace_depth) @@ -2483,7 +2501,8 @@ cp_parser_skip_to_closing_parenthesis (cp_parser *parser, break; case CPP_COMMA: - if (recovering && or_comma && !brace_depth && !paren_depth) + if (recovering && or_comma && !brace_depth && !paren_depth + && !square_depth) return -1; break; @@ -3283,6 +3302,20 @@ cp_parser_primary_expression (cp_parser *parser, return expr; } + case CPP_OPEN_SQUARE: + if (c_dialect_objc ()) + /* We have an Objective-C++ message. */ + return cp_parser_objc_expression (parser); + maybe_warn_cpp0x ("lambda expressions"); + return cp_parser_lambda_expression (parser); + + case CPP_OBJC_STRING: + if (c_dialect_objc ()) + /* We have an Objective-C++ string literal. */ + return cp_parser_objc_expression (parser); + cp_parser_error (parser, "expected primary-expression"); + return error_mark_node; + case CPP_KEYWORD: switch (token->keyword) { @@ -3540,13 +3573,6 @@ cp_parser_primary_expression (cp_parser *parser, /* Anything else is an error. */ default: - /* ...unless we have an Objective-C++ message or string literal, - that is. */ - if (c_dialect_objc () - && (token->type == CPP_OPEN_SQUARE - || token->type == CPP_OBJC_STRING)) - return cp_parser_objc_expression (parser); - cp_parser_error (parser, "expected primary-expression"); return error_mark_node; } @@ -6925,6 +6951,525 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) return finish_trait_expr (kind, type1, type2); } +/* Lambdas that appear in variable initializer or default argument scope + get that in their mangling, so we need to record it. We might as well + use the count for function and namespace scopes as well. */ +static tree lambda_scope; +static int lambda_count; +typedef struct GTY(()) tree_int +{ + tree t; + int i; +} tree_int; +DEF_VEC_O(tree_int); +DEF_VEC_ALLOC_O(tree_int,gc); +static GTY(()) VEC(tree_int,gc) *lambda_scope_stack; + +static void +start_lambda_scope (tree decl) +{ + tree_int ti; + gcc_assert (decl); + /* Once we're inside a function, we ignore other scopes and just push + the function again so that popping works properly. */ + if (current_function_decl && TREE_CODE (decl) != FUNCTION_DECL) + decl = current_function_decl; + ti.t = lambda_scope; + ti.i = lambda_count; + VEC_safe_push (tree_int, gc, lambda_scope_stack, &ti); + if (lambda_scope != decl) + { + /* Don't reset the count if we're still in the same function. */ + lambda_scope = decl; + lambda_count = 0; + } +} + +static void +record_lambda_scope (tree lambda) +{ + LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope; + LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++; +} + +static void +finish_lambda_scope (void) +{ + tree_int *p = VEC_last (tree_int, lambda_scope_stack); + if (lambda_scope != p->t) + { + lambda_scope = p->t; + lambda_count = p->i; + } + VEC_pop (tree_int, lambda_scope_stack); +} + +/* We want to determine the linkage of a lambda type at pushtag time, + before CLASSTYPE_LAMBDA_EXPR has been set. So this callback allows us + to find out whether the current lambda mangling scope will give us + linkage or not. */ + +bool +no_linkage_lambda_type_p (tree type) +{ + tree lambda, scope; + if (!LAMBDA_TYPE_P (type)) + return false; + + lambda = CLASSTYPE_LAMBDA_EXPR (type); + if (lambda) + scope = LAMBDA_EXPR_EXTRA_SCOPE (lambda); + else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + /* We can't use lambda_scope, and CLASSTYPE_TEMPLATE_INFO won't be set + yet either, so guess it's public for now. */ + return false; + else + scope = lambda_scope; + + return (scope == NULL_TREE); +} + +/* Parse a lambda expression. + + lambda-expression: + lambda-introducer lambda-declarator [opt] compound-statement + + Returns a representation of the expression. */ + +static tree +cp_parser_lambda_expression (cp_parser* parser) +{ + tree lambda_expr = build_lambda_expr (); + tree type; + + LAMBDA_EXPR_LOCATION (lambda_expr) + = cp_lexer_peek_token (parser->lexer)->location; + + /* We may be in the middle of deferred access check. Disable + it now. */ + push_deferring_access_checks (dk_no_deferred); + + type = begin_lambda_type (lambda_expr); + + record_lambda_scope (lambda_expr); + + { + /* Inside the class, surrounding template-parameter-lists do not apply. */ + unsigned int saved_num_template_parameter_lists + = parser->num_template_parameter_lists; + + parser->num_template_parameter_lists = 0; + + cp_parser_lambda_introducer (parser, lambda_expr); + + /* By virtue of defining a local class, a lambda expression has access to + the private variables of enclosing classes. */ + + cp_parser_lambda_declarator_opt (parser, lambda_expr); + + cp_parser_lambda_body (parser, lambda_expr); + + /* The capture list was built up in reverse order; fix that now. */ + { + tree newlist = NULL_TREE; + tree elt, next; + + for (elt = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); + elt; elt = next) + { + /* Also add __ to the beginning of the field name so that code + outside the lambda body can't see the captured name. We could + just remove the name entirely, but this is more useful for + debugging. */ + tree field = TREE_PURPOSE (elt); + char *buf + = (char *) alloca (IDENTIFIER_LENGTH (DECL_NAME (field)) + 3); + buf[1] = buf[0] = '_'; + memcpy (buf + 2, IDENTIFIER_POINTER (DECL_NAME (field)), + IDENTIFIER_LENGTH (DECL_NAME (field)) + 1); + DECL_NAME (field) = get_identifier (buf); + + next = TREE_CHAIN (elt); + TREE_CHAIN (elt) = newlist; + newlist = elt; + } + LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) = newlist; + } + + type = finish_struct (type, /*attributes=*/NULL_TREE); + + parser->num_template_parameter_lists = saved_num_template_parameter_lists; + } + + pop_deferring_access_checks (); + + return build_lambda_object (lambda_expr); +} + +/* Parse the beginning of a lambda expression. + + lambda-introducer: + [ lambda-capture [opt] ] + + LAMBDA_EXPR is the current representation of the lambda expression. */ + +static void +cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) +{ + /* Need commas after the first capture. */ + bool first = true; + + /* Eat the leading `['. */ + cp_parser_require (parser, CPP_OPEN_SQUARE, "%<[%>"); + + /* Record default capture mode. "[&" "[=" "[&," "[=," */ + if (cp_lexer_next_token_is (parser->lexer, CPP_AND) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_NAME) + LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_REFERENCE; + else if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) = CPLD_COPY; + + if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE) + { + cp_lexer_consume_token (parser->lexer); + first = false; + } + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)) + { + cp_token* capture_token; + tree capture_id; + tree capture_init_expr; + cp_id_kind idk = CP_ID_KIND_NONE; + + enum capture_kind_type + { + BY_COPY, + BY_REFERENCE + }; + enum capture_kind_type capture_kind = BY_COPY; + + if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + { + error ("expected end of capture-list"); + return; + } + + if (first) + first = false; + else + cp_parser_require (parser, CPP_COMMA, "%<,%>"); + + /* Possibly capture `this'. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THIS)) + { + cp_lexer_consume_token (parser->lexer); + add_capture (lambda_expr, + /*id=*/get_identifier ("__this"), + /*initializer=*/finish_this_expr(), + /*by_reference_p=*/false); + continue; + } + + /* Remember whether we want to capture as a reference or not. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_AND)) + { + capture_kind = BY_REFERENCE; + cp_lexer_consume_token (parser->lexer); + } + + /* Get the identifier. */ + capture_token = cp_lexer_peek_token (parser->lexer); + capture_id = cp_parser_identifier (parser); + + if (capture_id == error_mark_node) + /* Would be nice to have a cp_parser_skip_to_closing_x for general + delimiters, but I modified this to stop on unnested ']' as well. It + was already changed to stop on unnested '}', so the + "closing_parenthesis" name is no more misleading with my change. */ + { + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/true, + /*consume_paren=*/true); + continue; + } + + /* Find the initializer for this capture. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + /* An explicit expression exists. */ + cp_lexer_consume_token (parser->lexer); + pedwarn (input_location, OPT_pedantic, + "ISO C++ does not allow initializers " + "in lambda expression capture lists"); + capture_init_expr = cp_parser_assignment_expression (parser, + /*cast_p=*/true, + &idk); + } + else + { + const char* error_msg; + + /* Turn the identifier into an id-expression. */ + capture_init_expr + = cp_parser_lookup_name + (parser, + capture_id, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true, + /*ambiguous_decls=*/NULL, + capture_token->location); + + capture_init_expr + = finish_id_expression + (capture_id, + capture_init_expr, + parser->scope, + &idk, + /*integral_constant_expression_p=*/false, + /*allow_non_integral_constant_expression_p=*/false, + /*non_integral_constant_expression_p=*/NULL, + /*template_p=*/false, + /*done=*/true, + /*address_p=*/false, + /*template_arg_p=*/false, + &error_msg, + capture_token->location); + } + + if (TREE_CODE (capture_init_expr) == IDENTIFIER_NODE) + capture_init_expr + = unqualified_name_lookup_error (capture_init_expr); + + add_capture (lambda_expr, + capture_id, + capture_init_expr, + /*by_reference_p=*/capture_kind == BY_REFERENCE); + } + + cp_parser_require (parser, CPP_CLOSE_SQUARE, "%<]%>"); +} + +/* Parse the (optional) middle of a lambda expression. + + lambda-declarator: + ( parameter-declaration-clause [opt] ) + attribute-specifier [opt] + mutable [opt] + exception-specification [opt] + lambda-return-type-clause [opt] + + LAMBDA_EXPR is the current representation of the lambda expression. */ + +static void +cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) +{ + /* 5.1.1.4 of the standard says: + If a lambda-expression does not include a lambda-declarator, it is as if + the lambda-declarator were (). + This means an empty parameter list, no attributes, and no exception + specification. */ + tree param_list = void_list_node; + tree attributes = NULL_TREE; + tree exception_spec = NULL_TREE; + tree t; + + /* The lambda-declarator is optional, but must begin with an opening + parenthesis if present. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + cp_lexer_consume_token (parser->lexer); + + begin_scope (sk_function_parms, /*entity=*/NULL_TREE); + + /* Parse parameters. */ + param_list = cp_parser_parameter_declaration_clause (parser); + + /* Default arguments shall not be specified in the + parameter-declaration-clause of a lambda-declarator. */ + for (t = param_list; t; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t)) + pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_pedantic, + "default argument specified for lambda parameter"); + + cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>"); + + attributes = cp_parser_attributes_opt (parser); + + /* Parse optional `mutable' keyword. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_MUTABLE)) + { + cp_lexer_consume_token (parser->lexer); + LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1; + } + + /* Parse optional exception specification. */ + exception_spec = cp_parser_exception_specification_opt (parser); + + /* Parse optional trailing return type. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) + { + cp_lexer_consume_token (parser->lexer); + LAMBDA_EXPR_RETURN_TYPE (lambda_expr) = cp_parser_type_id (parser); + } + + /* The function parameters must be in scope all the way until after the + trailing-return-type in case of decltype. */ + for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) + pop_binding (DECL_NAME (t), t); + + leave_scope (); + } + + /* Create the function call operator. + + Messing with declarators like this is no uglier than building up the + FUNCTION_DECL by hand, and this is less likely to get out of sync with + other code. */ + { + cp_decl_specifier_seq return_type_specs; + cp_declarator* declarator; + tree fco; + int quals; + void *p; + + clear_decl_specs (&return_type_specs); + if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr)) + return_type_specs.type = LAMBDA_EXPR_RETURN_TYPE (lambda_expr); + else + /* Maybe we will deduce the return type later, but we can use void + as a placeholder return type anyways. */ + return_type_specs.type = void_type_node; + + p = obstack_alloc (&declarator_obstack, 0); + + declarator = make_id_declarator (NULL_TREE, ansi_opname (CALL_EXPR), + sfk_none); + + quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr) + ? TYPE_UNQUALIFIED : TYPE_QUAL_CONST); + declarator = make_call_declarator (declarator, param_list, quals, + exception_spec, + /*late_return_type=*/NULL_TREE); + + fco = grokmethod (&return_type_specs, + declarator, + attributes); + DECL_INITIALIZED_IN_CLASS_P (fco) = 1; + DECL_ARTIFICIAL (fco) = 1; + + finish_member_declaration (fco); + + obstack_free (&declarator_obstack, p); + } +} + +/* Parse the body of a lambda expression, which is simply + + compound-statement + + but which requires special handling. + LAMBDA_EXPR is the current representation of the lambda expression. */ + +static void +cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) +{ + bool nested = (current_function_decl != NULL_TREE); + if (nested) + push_function_context (); + + /* Finish the function call operator + - class_specifier + + late_parsing_for_member + + function_definition_after_declarator + + ctor_initializer_opt_and_function_body */ + { + tree fco = lambda_function (lambda_expr); + tree body; + bool done = false; + + /* Let the front end know that we are going to be defining this + function. */ + start_preparsed_function (fco, + NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + + start_lambda_scope (fco); + body = begin_function_body (); + + /* 5.1.1.4 of the standard says: + If a lambda-expression does not include a trailing-return-type, it + is as if the trailing-return-type denotes the following type: + — if the compound-statement is of the form + { return attribute-specifier [opt] expression ; } + the type of the returned expression after lvalue-to-rvalue + conversion (_conv.lval_ 4.1), array-to-pointer conversion + (_conv.array_ 4.2), and function-to-pointer conversion + (_conv.func_ 4.3); + — otherwise, void. */ + + /* In a lambda that has neither a lambda-return-type-clause + nor a deducible form, errors should be reported for return statements + in the body. Since we used void as the placeholder return type, parsing + the body as usual will give such desired behavior. */ + if (!LAMBDA_EXPR_RETURN_TYPE (lambda_expr) + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE) + && cp_lexer_peek_nth_token (parser->lexer, 2)->keyword == RID_RETURN + && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_SEMICOLON) + { + tree compound_stmt; + tree expr = NULL_TREE; + cp_id_kind idk = CP_ID_KIND_NONE; + + /* Parse tentatively in case there's more after the initial return + statement. */ + cp_parser_parse_tentatively (parser); + + cp_parser_require (parser, CPP_OPEN_BRACE, "%<{%>"); + cp_parser_require_keyword (parser, RID_RETURN, "%"); + + expr = cp_parser_expression (parser, /*cast_p=*/false, &idk); + + cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); + cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>"); + + if (cp_parser_parse_definitely (parser)) + { + apply_lambda_return_type (lambda_expr, lambda_return_type (expr)); + + compound_stmt = begin_compound_stmt (0); + /* Will get error here if type not deduced yet. */ + finish_return_stmt (expr); + finish_compound_stmt (compound_stmt); + + done = true; + } + } + + if (!done) + { + if (!LAMBDA_EXPR_RETURN_TYPE (lambda_expr)) + LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = true; + /* TODO: does begin_compound_stmt want BCS_FN_BODY? + cp_parser_compound_stmt does not pass it. */ + cp_parser_function_body (parser); + LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = false; + } + + finish_function_body (body); + finish_lambda_scope (); + + /* Finish the function and generate code for it if necessary. */ + expand_or_defer_fn (finish_function (/*inline*/2)); + } + + if (nested) + pop_function_context(); +} + /* Statements [gram.stmt.stmt] */ /* Parse a statement. @@ -13033,9 +13578,21 @@ cp_parser_init_declarator (cp_parser* parser, } } else - initializer = cp_parser_initializer (parser, - &is_direct_init, - &is_non_constant_init); + { + /* We want to record the extra mangling scope for in-class + initializers of class members and initializers of static data + member templates. The former is a C++0x feature which isn't + implemented yet, and I expect it will involve deferring + parsing of the initializer until end of class as with default + arguments. So right here we only handle the latter. */ + if (!member_p && processing_template_decl) + start_lambda_scope (decl); + initializer = cp_parser_initializer (parser, + &is_direct_init, + &is_non_constant_init); + if (!member_p && processing_template_decl) + finish_lambda_scope (); + } } /* The old parser allows attributes to appear after a parenthesized @@ -14453,7 +15010,8 @@ cp_parser_parameter_declaration (cp_parser *parser, /* If we are defining a class, then the tokens that make up the default argument must be saved and processed later. */ if (!template_parm_p && at_class_scope_p () - && TYPE_BEING_DEFINED (current_class_type)) + && TYPE_BEING_DEFINED (current_class_type) + && !LAMBDA_TYPE_P (current_class_type)) { unsigned depth = 0; int maybe_template_id = 0; @@ -17841,7 +18399,7 @@ cp_parser_function_definition_from_specifiers_and_declarator /* Parse the part of a function-definition that follows the declarator. INLINE_P is TRUE iff this function is an inline - function defined with a class-specifier. + function defined within a class-specifier. Returns the function defined. */ @@ -17893,6 +18451,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, saved_num_template_parameter_lists = parser->num_template_parameter_lists; parser->num_template_parameter_lists = 0; + + start_lambda_scope (current_function_decl); + /* If the next token is `try', then we are looking at a function-try-block. */ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) @@ -17903,6 +18464,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body (parser); + finish_lambda_scope (); + /* Finish the function. */ fn = finish_function ((ctor_initializer_p ? 1 : 0) | (inline_p ? 2 : 0)); @@ -18530,7 +19093,7 @@ static void cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) { bool saved_local_variables_forbidden_p; - tree parm; + tree parm, parmdecl; /* While we're parsing the default args, we might (due to the statement expression extension) encounter more classes. We want @@ -18544,9 +19107,11 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; parser->local_variables_forbidden_p = true; - for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn)); - parm; - parm = TREE_CHAIN (parm)) + for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn)), + parmdecl = DECL_ARGUMENTS (fn); + parm && parm != void_list_node; + parm = TREE_CHAIN (parm), + parmdecl = TREE_CHAIN (parmdecl)) { cp_token_cache *tokens; tree default_arg = TREE_PURPOSE (parm); @@ -18568,6 +19133,8 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) tokens = DEFARG_TOKENS (default_arg); cp_parser_push_lexer_for_tokens (parser, tokens); + start_lambda_scope (parmdecl); + /* Parse the assignment-expression. */ parsed_arg = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL); if (parsed_arg == error_mark_node) @@ -18586,6 +19153,8 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) VEC_iterate (tree, insts, ix, copy); ix++) TREE_PURPOSE (copy) = parsed_arg; + finish_lambda_scope (); + /* If the token stream has not been completely used up, then there was extra junk after the end of the default argument. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 08964dab271..86b4d9e43bc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -300,7 +300,7 @@ get_template_info (const_tree t) if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) tinfo = DECL_TEMPLATE_INFO (t); - if (!tinfo && TREE_CODE (t) == TYPE_DECL) + if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t)) t = TREE_TYPE (t); if (TAGGED_TYPE_P (t)) @@ -6230,6 +6230,7 @@ lookup_template_class (tree d1, if (!is_partial_instantiation && !PRIMARY_TEMPLATE_P (gen_tmpl) + && !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl)) && TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL) { found = xref_tag_from_type (TREE_TYPE (gen_tmpl), @@ -9162,6 +9163,22 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE); SET_DECL_IMPLICIT_INSTANTIATION (r); } + else if (cp_unevaluated_operand) + { + /* We're substituting this var in a decltype outside of its + scope, such as for a lambda return type. Don't add it to + local_specializations, do perform auto deduction. */ + tree auto_node = type_uses_auto (type); + tree init + = tsubst_expr (DECL_INITIAL (t), args, complain, in_decl, + /*constant_expression_p=*/false); + + if (auto_node && init && describable_type (init)) + { + type = do_auto_deduction (type, init, auto_node); + TREE_TYPE (r) = type; + } + } else register_local_specialization (r, t); @@ -10153,9 +10170,13 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) --cp_unevaluated_operand; --c_inhibit_evaluation_warnings; - type = - finish_decltype_type (type, - DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t)); + if (DECLTYPE_FOR_LAMBDA_CAPTURE (t)) + type = lambda_capture_field_type (type); + else if (DECLTYPE_FOR_LAMBDA_RETURN (t)) + type = lambda_return_type (type); + else + type = finish_decltype_type + (type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t)); return cp_build_qualified_type_real (type, cp_type_quals (t) | cp_type_quals (type), @@ -12359,6 +12380,39 @@ tsubst_copy_and_build (tree t, } return t; + case LAMBDA_EXPR: + { + tree r = build_lambda_expr (); + + tree type = tsubst (TREE_TYPE (t), args, complain, NULL_TREE); + TREE_TYPE (r) = type; + CLASSTYPE_LAMBDA_EXPR (type) = r; + + LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r) + = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t); + LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t); + LAMBDA_EXPR_DISCRIMINATOR (r) + = (LAMBDA_EXPR_DISCRIMINATOR (t)); + LAMBDA_EXPR_CAPTURE_LIST (r) + = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t)); + LAMBDA_EXPR_THIS_CAPTURE (r) + = RECUR (LAMBDA_EXPR_THIS_CAPTURE (t)); + LAMBDA_EXPR_EXTRA_SCOPE (r) + = RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t)); + + /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */ + determine_visibility (TYPE_NAME (type)); + /* Now that we know visibility, instantiate the type so we have a + declaration of the op() for later calls to lambda_function. */ + complete_type (type); + + type = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl); + if (type) + apply_lambda_return_type (r, type); + + return build_lambda_object (r); + } + default: /* Handle Objective-C++ constructs, if appropriate. */ { @@ -15959,10 +16013,11 @@ instantiate_decl (tree d, int defer_ok, SET_DECL_IMPLICIT_INSTANTIATION (d); } - if (!defer_ok) + /* Recheck the substitutions to obtain any warning messages + about ignoring cv qualifiers. Don't do this for artificial decls, + as it breaks the context-sensitive substitution for lambda op(). */ + if (!defer_ok && !DECL_ARTIFICIAL (d)) { - /* Recheck the substitutions to obtain any warning messages - about ignoring cv qualifiers. */ tree gen = DECL_TEMPLATE_RESULT (gen_tmpl); tree type = TREE_TYPE (gen); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index c50cc4a0841..d6521fb6f82 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1380,6 +1380,8 @@ lookup_fnfields_1 (tree type, tree name) lazily_declare_fn (sfk_constructor, type); if (CLASSTYPE_LAZY_COPY_CTOR (type)) lazily_declare_fn (sfk_copy_constructor, type); + if (CLASSTYPE_LAZY_MOVE_CTOR (type)) + lazily_declare_fn (sfk_move_constructor, type); } else if (name == ansi_assopname(NOP_EXPR) && CLASSTYPE_LAZY_ASSIGNMENT_OP (type)) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6b741b3ebe5..6dec9f8a339 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); +static tree capture_decltype (tree); /* Deferred Access Checking Overview @@ -1445,6 +1446,21 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) return error_mark_node; } + + /* If decl is a field, object has a lambda type, and decl is not a member + of that type, then we have a reference to a member of 'this' from a + lambda inside a non-static member function, and we must get to decl + through the 'this' capture. If decl is not a member of that object, + either, then its access will still fail later. */ + if (LAMBDA_TYPE_P (TREE_TYPE (object)) + && !same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (decl), + TREE_TYPE (object))) + object = cp_build_indirect_ref (lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR + (TREE_TYPE (object))), + /*errorstring=*/"", + /*complain=*/tf_warning_or_error); + if (current_class_ptr) TREE_USED (current_class_ptr) = 1; if (processing_template_decl && !qualifying_scope) @@ -2049,7 +2065,14 @@ finish_this_expr (void) if (current_class_ptr) { - result = current_class_ptr; + tree type = TREE_TYPE (current_class_ref); + + /* In a lambda expression, 'this' refers to the captured 'this'. */ + if (LAMBDA_TYPE_P (type)) + result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type)); + else + result = current_class_ptr; + } else if (current_function_decl && DECL_STATIC_FUNCTION_P (current_function_decl)) @@ -2613,6 +2636,18 @@ baselink_for_fns (tree fns) return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE); } +/* Returns true iff DECL is an automatic variable from a function outside + the current one. */ + +static bool +outer_automatic_var_p (tree decl) +{ + return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + && DECL_FUNCTION_SCOPE_P (decl) + && !TREE_STATIC (decl) + && DECL_CONTEXT (decl) != current_function_decl); +} + /* ID_EXPRESSION is a representation of parsed, but unprocessed, id-expression. (See cp_parser_id_expression for details.) SCOPE, if non-NULL, is the type or namespace used to explicitly qualify @@ -2714,12 +2749,61 @@ finish_id_expression (tree id_expression, if (!scope && decl != error_mark_node) maybe_note_name_used_in_class (id_expression, decl); - /* Disallow uses of local variables from containing functions. */ - if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + /* Disallow uses of local variables from containing functions, except + within lambda-expressions. */ + if (outer_automatic_var_p (decl) + /* It's not a use (3.2) if we're in an unevaluated context. */ + && !cp_unevaluated_operand) { - tree context = decl_function_context (decl); - if (context != NULL_TREE && context != current_function_decl - && ! TREE_STATIC (decl)) + tree context = DECL_CONTEXT (decl); + tree containing_function = current_function_decl; + tree lambda_stack = NULL_TREE; + tree lambda_expr = NULL_TREE; + + /* Core issue 696: "[At the July 2009 meeting] the CWG expressed + support for an approach in which a reference to a local + [constant] automatic variable in a nested class or lambda body + would enter the expression as an rvalue, which would reduce + the complexity of the problem" + + FIXME update for final resolution of core issue 696. */ + if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)) + return integral_constant_value (decl); + + /* If we are in a lambda function, we can move out until we hit + 1. the context, + 2. a non-lambda function, or + 3. a non-default capturing lambda function. */ + while (context != containing_function + && LAMBDA_FUNCTION_P (containing_function)) + { + lambda_expr = CLASSTYPE_LAMBDA_EXPR + (DECL_CONTEXT (containing_function)); + + if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) + == CPLD_NONE) + break; + + lambda_stack = tree_cons (NULL_TREE, + lambda_expr, + lambda_stack); + + containing_function + = decl_function_context (containing_function); + } + + if (context == containing_function) + { + decl = add_default_capture (lambda_stack, + /*id=*/DECL_NAME (decl), + /*initializer=*/decl); + } + else if (lambda_expr) + { + error ("%qD is not captured", decl); + return error_mark_node; + } + else { error (TREE_CODE (decl) == VAR_DECL ? "use of % variable from containing function" @@ -4788,6 +4872,18 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) if (real_lvalue_p (expr)) type = build_reference_type (type); } + /* Within a lambda-expression: + + Every occurrence of decltype((x)) where x is a possibly + parenthesized id-expression that names an entity of + automatic storage duration is treated as if x were + transformed into an access to a corresponding data member + of the closure type that would have been declared if x + were a use of the denoted entity. */ + else if (outer_automatic_var_p (expr) + && current_function_decl + && LAMBDA_FUNCTION_P (current_function_decl)) + type = capture_decltype (expr); else { /* Otherwise, where T is the type of e, if e is an lvalue, @@ -4842,6 +4938,8 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p) it now. */ if (CLASSTYPE_LAZY_COPY_CTOR (type)) lazily_declare_fn (sfk_copy_constructor, type); + if (CLASSTYPE_LAZY_MOVE_CTOR (type)) + lazily_declare_fn (sfk_move_constructor, type); fns = CLASSTYPE_CONSTRUCTORS (type); } else @@ -5105,4 +5203,416 @@ float_const_decimal64_p (void) return 0; } +/* Constructor for a lambda expression. */ + +tree +build_lambda_expr (void) +{ + tree lambda = make_node (LAMBDA_EXPR); + LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE; + LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE; + LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE; + LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE; + LAMBDA_EXPR_MUTABLE_P (lambda) = false; + return lambda; +} + +/* Create the closure object for a LAMBDA_EXPR. */ + +tree +build_lambda_object (tree lambda_expr) +{ + /* Build aggregate constructor call. + - cp_parser_braced_list + - cp_parser_functional_cast */ + VEC(constructor_elt,gc) *elts = NULL; + tree node, expr, type; + location_t saved_loc; + + if (processing_template_decl) + return lambda_expr; + + /* Make sure any error messages refer to the lambda-introducer. */ + saved_loc = input_location; + input_location = LAMBDA_EXPR_LOCATION (lambda_expr); + + for (node = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); + node; + node = TREE_CHAIN (node)) + { + tree field = TREE_PURPOSE (node); + tree val = TREE_VALUE (node); + + /* Mere mortals can't copy arrays with aggregate initialization, so + do some magic to make it work here. */ + if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) + val = build_array_copy (val); + + CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val); + } + + expr = build_constructor (init_list_type_node, elts); + CONSTRUCTOR_IS_DIRECT_INIT (expr) = 1; + + /* N2927: "[The closure] class type is not an aggregate." + But we briefly treat it as an aggregate to make this simpler. */ + type = TREE_TYPE (lambda_expr); + CLASSTYPE_NON_AGGREGATE (type) = 0; + expr = finish_compound_literal (type, expr); + CLASSTYPE_NON_AGGREGATE (type) = 1; + + input_location = saved_loc; + return expr; +} + +/* Return an initialized RECORD_TYPE for LAMBDA. + LAMBDA must have its explicit captures already. */ + +tree +begin_lambda_type (tree lambda) +{ + tree type; + + { + /* Unique name. This is just like an unnamed class, but we cannot use + make_anon_name because of certain checks against TYPE_ANONYMOUS_P. */ + tree name; + name = make_lambda_name (); + + /* Create the new RECORD_TYPE for this lambda. */ + type = xref_tag (/*tag_code=*/record_type, + name, + /*scope=*/ts_within_enclosing_non_class, + /*template_header_p=*/false); + } + + /* Designate it as a struct so that we can use aggregate initialization. */ + CLASSTYPE_DECLARED_CLASS (type) = false; + + /* Clear base types. */ + xref_basetypes (type, /*bases=*/NULL_TREE); + + /* Start the class. */ + type = begin_class_definition (type, /*attributes=*/NULL_TREE); + + /* Cross-reference the expression and the type. */ + TREE_TYPE (lambda) = type; + CLASSTYPE_LAMBDA_EXPR (type) = lambda; + + return type; +} + +/* Returns the type to use for the return type of the operator() of a + closure class. */ + +tree +lambda_return_type (tree expr) +{ + tree type; + if (type_dependent_expression_p (expr)) + { + type = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (type) = expr; + DECLTYPE_FOR_LAMBDA_RETURN (type) = true; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } + else + type = type_decays_to (unlowered_expr_type (expr)); + return type; +} + +/* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the + closure type. */ + +tree +lambda_function (tree lambda) +{ + tree type; + if (TREE_CODE (lambda) == LAMBDA_EXPR) + type = TREE_TYPE (lambda); + else + type = lambda; + gcc_assert (LAMBDA_TYPE_P (type)); + /* Don't let debug_tree cause instantiation. */ + if (CLASSTYPE_TEMPLATE_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) + return NULL_TREE; + lambda = lookup_member (type, ansi_opname (CALL_EXPR), + /*protect=*/0, /*want_type=*/false); + if (lambda) + lambda = BASELINK_FUNCTIONS (lambda); + return lambda; +} + +/* Returns the type to use for the FIELD_DECL corresponding to the + capture of EXPR. + The caller should add REFERENCE_TYPE for capture by reference. */ + +tree +lambda_capture_field_type (tree expr) +{ + tree type; + if (type_dependent_expression_p (expr)) + { + type = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (type) = expr; + DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } + else + type = non_reference (unlowered_expr_type (expr)); + return type; +} + +/* Recompute the return type for LAMBDA with body of the form: + { return EXPR ; } */ + +void +apply_lambda_return_type (tree lambda, tree return_type) +{ + tree fco = lambda_function (lambda); + tree result; + + LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type; + + /* If we got a DECLTYPE_TYPE, don't stick it in the function yet, + it would interfere with instantiating the closure type. */ + if (dependent_type_p (return_type)) + return; + if (return_type == error_mark_node) + return; + + /* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE + TREE_TYPE (METHOD_TYPE) == return-type */ + TREE_TYPE (TREE_TYPE (fco)) = return_type; + + result = DECL_RESULT (fco); + if (result == NULL_TREE) + return; + + /* We already have a DECL_RESULT from start_preparsed_function. + Now we need to redo the work it and allocate_struct_function + did to reflect the new type. */ + result = build_decl (input_location, RESULT_DECL, NULL_TREE, + TYPE_MAIN_VARIANT (return_type)); + DECL_ARTIFICIAL (result) = 1; + DECL_IGNORED_P (result) = 1; + cp_apply_type_quals_to_decl (cp_type_quals (return_type), + result); + + DECL_RESULT (fco) = result; + + if (!processing_template_decl && aggregate_value_p (result, fco)) + { +#ifdef PCC_STATIC_STRUCT_RETURN + cfun->returns_pcc_struct = 1; +#endif + cfun->returns_struct = 1; + } + +} + +/* DECL is a local variable or parameter from the surrounding scope of a + lambda-expression. Returns the decltype for a use of the capture field + for DECL even if it hasn't been captured yet. */ + +static tree +capture_decltype (tree decl) +{ + tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl)); + /* FIXME do lookup instead of list walk? */ + tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam)); + tree type; + + if (cap) + type = TREE_TYPE (TREE_PURPOSE (cap)); + else + switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam)) + { + case CPLD_NONE: + error ("%qD is not captured", decl); + return error_mark_node; + + case CPLD_COPY: + type = TREE_TYPE (decl); + if (TREE_CODE (type) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) + type = TREE_TYPE (type); + break; + + case CPLD_REFERENCE: + type = TREE_TYPE (decl); + if (TREE_CODE (type) != REFERENCE_TYPE) + type = build_reference_type (TREE_TYPE (decl)); + break; + + default: + gcc_unreachable (); + } + + if (TREE_CODE (type) != REFERENCE_TYPE) + { + if (!LAMBDA_EXPR_MUTABLE_P (lam)) + type = cp_build_qualified_type (type, (TYPE_QUALS (type) + |TYPE_QUAL_CONST)); + type = build_reference_type (type); + } + return type; +} + +/* From an ID and INITIALIZER, create a capture (by reference if + BY_REFERENCE_P is true), add it to the capture-list for LAMBDA, + and return it. */ + +tree +add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) +{ + tree type; + tree member; + + type = lambda_capture_field_type (initializer); + if (by_reference_p) + { + type = build_reference_type (type); + if (!real_lvalue_p (initializer)) + error ("cannot capture %qE by reference", initializer); + } + + /* Make member variable. */ + member = build_lang_decl (FIELD_DECL, id, type); + + /* Add it to the appropriate closure class. */ + finish_member_declaration (member); + + LAMBDA_EXPR_CAPTURE_LIST (lambda) + = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda)); + + if (id == get_identifier ("__this")) + { + if (LAMBDA_EXPR_CAPTURES_THIS_P (lambda)) + error ("already captured % in lambda expression"); + LAMBDA_EXPR_THIS_CAPTURE (lambda) = member; + } + + return member; +} + +/* Similar to add_capture, except this works on a stack of nested lambdas. + BY_REFERENCE_P in this case is derived from the default capture mode. + Returns the capture for the lambda at the bottom of the stack. */ + +tree +add_default_capture (tree lambda_stack, tree id, tree initializer) +{ + bool this_capture_p = (id == get_identifier ("__this")); + + tree member = NULL_TREE; + + tree saved_class_type = current_class_type; + + tree node; + + for (node = lambda_stack; + node; + node = TREE_CHAIN (node)) + { + tree lambda = TREE_VALUE (node); + + current_class_type = TREE_TYPE (lambda); + member = add_capture (lambda, + id, + initializer, + /*by_reference_p=*/ + (!this_capture_p + && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) + == CPLD_REFERENCE))); + + { + /* Have to get the old value of current_class_ref. */ + tree object = cp_build_indirect_ref (DECL_ARGUMENTS + (lambda_function (lambda)), + /*errorstring=*/"", + /*complain=*/tf_warning_or_error); + initializer = finish_non_static_data_member + (member, object, /*qualifying_scope=*/NULL_TREE); + } + } + + current_class_type = saved_class_type; + + return member; + +} + +/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an + INDIRECT_REF, possibly adding it through default capturing. */ + +tree +lambda_expr_this_capture (tree lambda) +{ + tree result; + + tree this_capture = LAMBDA_EXPR_THIS_CAPTURE (lambda); + + /* Try to default capture 'this' if we can. */ + if (!this_capture + && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE) + { + tree containing_function = TYPE_CONTEXT (TREE_TYPE (lambda)); + tree lambda_stack = tree_cons (NULL_TREE, lambda, NULL_TREE); + + /* If we are in a lambda function, we can move out until we hit: + 1. a non-lambda function, + 2. a lambda function capturing 'this', or + 3. a non-default capturing lambda function. */ + while (LAMBDA_FUNCTION_P (containing_function)) + { + tree lambda + = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function)); + + if (LAMBDA_EXPR_THIS_CAPTURE (lambda) + || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_NONE) + break; + + lambda_stack = tree_cons (NULL_TREE, + lambda, + lambda_stack); + + containing_function = decl_function_context (containing_function); + } + + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function)) + { + this_capture = add_default_capture (lambda_stack, + /*id=*/get_identifier ("__this"), + /* First parameter is 'this'. */ + /*initializer=*/DECL_ARGUMENTS + (containing_function)); + } + + } + + if (!this_capture) + { + error ("% was not captured for this lambda function"); + result = error_mark_node; + } + else + { + /* To make sure that current_class_ref is for the lambda. */ + gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) == TREE_TYPE (lambda)); + + result = finish_non_static_data_member (this_capture, + current_class_ref, + /*qualifying_scope=*/NULL_TREE); + + /* If 'this' is captured, each use of 'this' is transformed into an + access to the corresponding unnamed data member of the closure + type cast (_expr.cast_ 5.4) to the type of 'this'. [ The cast + ensures that the transformed expression is an rvalue. ] */ + result = rvalue (result); + } + + return result; +} + #include "gt-cp-semantics.h" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index fb812e23303..7476aa03a43 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -456,6 +456,22 @@ build_cplus_new (tree type, tree init) return rval; } +/* Return a TARGET_EXPR which expresses the direct-initialization of one + array from another. */ + +tree +build_array_copy (tree init) +{ + tree type = TREE_TYPE (init); + tree slot = build_local_temp (type); + init = build2 (VEC_INIT_EXPR, type, slot, init); + SET_EXPR_LOCATION (init, input_location); + init = build_target_expr (slot, init); + TARGET_EXPR_IMPLICIT_P (init) = 1; + + return init; +} + /* Build a TARGET_EXPR using INIT to initialize a new temporary of the indicated TYPE. */ @@ -726,6 +742,17 @@ cp_build_reference_type (tree to_type, bool rval) } +/* Returns EXPR cast to rvalue reference type, like std::move. */ + +tree +move (tree expr) +{ + tree type = TREE_TYPE (expr); + gcc_assert (TREE_CODE (type) != REFERENCE_TYPE); + type = cp_build_reference_type (type, /*rval*/true); + return build_static_cast (type, expr, tf_warning_or_error); +} + /* Used by the C++ front end to build qualified array types. However, the C version of this function does not properly maintain canonical types (which are not used in C). */ @@ -1558,6 +1585,8 @@ no_linkage_check (tree t, bool relaxed_p) namespace scope. This doesn't have a core issue number yet. */ if (TYPE_ANONYMOUS_P (t) && TYPE_NAMESPACE_SCOPE_P (t)) return t; + if (no_linkage_lambda_type_p (t)) + return t; r = CP_TYPE_CONTEXT (t); if (TYPE_P (r)) @@ -2759,6 +2788,8 @@ special_function_p (const_tree decl) DECL_LANG_SPECIFIC. */ if (DECL_COPY_CONSTRUCTOR_P (decl)) return sfk_copy_constructor; + if (DECL_MOVE_CONSTRUCTOR_P (decl)) + return sfk_move_constructor; if (DECL_CONSTRUCTOR_P (decl)) return sfk_constructor; if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 059511396c5..b4d54fc4089 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1161,6 +1161,10 @@ structural_comptypes (tree t1, tree t2, int strict) case DECLTYPE_TYPE: if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2) + || (DECLTYPE_FOR_LAMBDA_CAPTURE (t1) + != DECLTYPE_FOR_LAMBDA_CAPTURE (t2)) + || (DECLTYPE_FOR_LAMBDA_RETURN (t1) + != DECLTYPE_FOR_LAMBDA_RETURN (t2)) || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), DECLTYPE_TYPE_EXPR (t2))) return false; @@ -7001,6 +7005,31 @@ check_return_expr (tree retval, bool *no_warning) return NULL_TREE; } + /* As an extension, deduce lambda return type from a return statement + anywhere in the body. */ + if (retval && LAMBDA_FUNCTION_P (current_function_decl)) + { + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); + if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda)) + { + tree type = lambda_return_type (retval); + tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda); + + if (VOID_TYPE_P (type)) + { /* Nothing. */ } + else if (oldtype == NULL_TREE) + { + pedwarn (input_location, OPT_pedantic, "lambda return type " + "can only be deduced when the return statement is " + "the only statement in the function body"); + apply_lambda_return_type (lambda, type); + } + else if (!same_type_p (type, oldtype)) + error ("inconsistent types %qT and %qT deduced for " + "lambda return type", type, oldtype); + } + } + if (processing_template_decl) { current_function_returns_value = 1; diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index d68383e380a..96fa442f6d1 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -838,6 +838,12 @@ digest_init_r (tree type, tree init, bool nested, int flags) if (TREE_CODE (type) == ARRAY_TYPE && TREE_CODE (init) != CONSTRUCTOR) { + /* Allow the result of build_array_copy. */ + if (TREE_CODE (init) == TARGET_EXPR + && (same_type_ignoring_top_level_qualifiers_p + (type, TREE_TYPE (init)))) + return init; + error ("array must be initialized with a brace-enclosed" " initializer"); return error_mark_node; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8128a9092ce..4a7961c807b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,46 @@ +2009-09-29 John Freeman + Jason Merrill + + * g++.dg/cpp0x/lambda/lambda-array.C: New. + * g++.dg/cpp0x/lambda/lambda-capture-const-ref.C: New. + * g++.dg/cpp0x/lambda/lambda-capture-const-ref-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-const.C: New. + * g++.dg/cpp0x/lambda/lambda-copy-default-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-copy-default.C: New. + * g++.dg/cpp0x/lambda/lambda-copy-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-copy.C: New. + * g++.dg/cpp0x/lambda/lambda-ctor-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-ctors.C: New. + * g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C: New. + * g++.dg/cpp0x/lambda/lambda-deduce-ext.C: New. + * g++.dg/cpp0x/lambda/lambda-deduce-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-deduce.C: New. + * g++.dg/cpp0x/lambda/lambda-defarg.C: New. + * g++.dg/cpp0x/lambda/lambda-eh.C: New. + * g++.dg/cpp0x/lambda/lambda-errloc.C: New. + * g++.dg/cpp0x/lambda/lambda-field-names.C: New. + * g++.dg/cpp0x/lambda/lambda-in-class-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-in-class.C: New. + * g++.dg/cpp0x/lambda/lambda-lookup-neg.C: New. + * g++.dg/cpp0x/lambda/lambda-mangle.C: New. + * g++.dg/cpp0x/lambda/lambda-mixed.C: New. + * g++.dg/cpp0x/lambda/lambda-mutable.C: New. + * g++.dg/cpp0x/lambda/lambda-nested.C: New. + * g++.dg/cpp0x/lambda/lambda-non-const.C: New. + * g++.dg/cpp0x/lambda/lambda-nop.C: New. + * g++.dg/cpp0x/lambda/lambda-ns-scope.C: New. + * g++.dg/cpp0x/lambda/lambda-pass.C: New. + * g++.dg/cpp0x/lambda/lambda-recursive.C: New. + * g++.dg/cpp0x/lambda/lambda-ref-default.C: New. + * g++.dg/cpp0x/lambda/lambda-ref.C: New. + * g++.dg/cpp0x/lambda/lambda-std-function.C: New. + * g++.dg/cpp0x/lambda/lambda-template.C: New. + * g++.dg/cpp0x/lambda/lambda-this.C: New. + * g++.dg/cpp0x/lambda/lambda-type.C: New. + * g++.dg/cpp0x/lambda/lambda-use.C: New. + * lib/prune.exp: Accept "In lambda function". + 2009-09-29 Harsha Jagasia * gcc.target/i386/fma4-check.h diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-array.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-array.C new file mode 100644 index 00000000000..2129051ed72 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-array.C @@ -0,0 +1,20 @@ +// Test that array capture by copy works. +// { dg-options -std=c++0x } +// { dg-do run } + +struct A +{ + int i; + A(int i): i(i) {} + A(const A& a): i(a.i+1) {} +}; + +int main() +{ + A ar[4][3] = { { 10, 20, 30 }, + { 40, 50, 60 }, + { 70, 80, 90 }, + { 100, 110, 120 } }; + int i = [ar] { return ar[1][1]; }().i; + return (i!= 52); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref-neg.C new file mode 100644 index 00000000000..7d1a1bd89d2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref-neg.C @@ -0,0 +1,14 @@ +// { dg-options "-std=c++0x" } +#include + +int main() { + int i = 1, j = 2; + const int& ci = i; + [&ci, &j] () -> void { j = ci; } (); + assert(i == 1); + assert(j == 1); + [&ci] () -> void { ci = 0; } (); // { dg-error "" "cannot assign to const int&" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref.C new file mode 100644 index 00000000000..f9cb2d53de2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const-ref.C @@ -0,0 +1,15 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } +#include + +int main() { + int i = 1, j = 2; + const int& ci = i; + [&ci, &j] () -> void { j = ci; } (); + assert(i == 1); + assert(j == 1); + //[&ci] () -> void { ci = 0; } (); { dg-error: cannot assign to const int& } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C new file mode 100644 index 00000000000..f48c6c243d6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-neg.C @@ -0,0 +1,19 @@ +// { dg-options "-std=c++0x" } + +#include + +template +void call(const F& f) { f(); } // { dg-error "discards qualifiers" } + +int main() { + call([] () -> void {}); + call([] () mutable -> void {}); // { dg-message "" "`f' does not have const `operator()'" } + + int i = -1; + call([&i] () -> void { i = 0; }); + assert(i == 0); + call([i] () -> void { i = 0; }); // { dg-error "" "assignment to non-reference capture in const lambda" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const.C new file mode 100644 index 00000000000..5bceb9227e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const.C @@ -0,0 +1,20 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include + +template +void call(const F& f) { f(); } + +int main() { + call([] () -> void {}); + //call([] () mutable -> void {}); // { dg-error: "`f' does not have const `operator()'" } + + int i = -1; + call([&i] () -> void { i = 0; }); + assert(i == 0); + //call([i] () -> void { i = 0; }); // { dg-error: "assignment to non-reference capture in const lambda" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default-neg.C new file mode 100644 index 00000000000..1af2a95d8a6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default-neg.C @@ -0,0 +1,13 @@ +// { dg-options "-std=c++0x" } + +int main() { + int i; + const char* s; + [=] () -> void { i; s; i; s; } (); + + [] () -> void { i; } (); // { dg-error "" "`i' is not captured" } + [1] () -> void {} (); // { dg-error "expected identifier" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default.C new file mode 100644 index 00000000000..4d4faea470b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-default.C @@ -0,0 +1,14 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +int main() { + int i; + const char* s; + [=] () -> void { i; s; i; s; } (); + + //[] () -> void { i; } (); // { dg-error: "`i' is not in scope" } + //[1] () -> void {} (); // { dg-error: "expected identifier" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-neg.C new file mode 100644 index 00000000000..d77e57e6310 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy-neg.C @@ -0,0 +1,13 @@ +// { dg-options "-std=c++0x" } + +int main() { + int i; + const char* s; + [i, s] () -> void { i; s; } (); + + [] () -> void { i; } (); // { dg-error "" "`i' is not captured" } + [1] () -> void {} (); // { dg-error "expected identifier" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy.C new file mode 100644 index 00000000000..d57a01d43e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-copy.C @@ -0,0 +1,14 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +int main() { + int i; + const char* s; + [i, s] () -> void { i; s; } (); + + //[] () -> void { i; } (); // { dg-error: "`i' is not in scope" } + //[1] () -> void {} (); // { dg-error: "expected identifier" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctor-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctor-neg.C new file mode 100644 index 00000000000..c38f2955d46 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctor-neg.C @@ -0,0 +1,25 @@ +// { dg-options -std=c++0x } + +void f() +{ + int i; + auto lam = [i]{}; // { dg-message "note" } + decltype(lam) lam2 = { 1 }; // { dg-error "" "not an aggregate" } + decltype(lam) lam3; // { dg-error "" "deleted default ctor" } + lam3 = lam; // { dg-error "" "deleted assignment op" } +} + +template +void g(T i) +{ + auto lam = [i]{}; // { dg-message "note" } + decltype(lam) lam2 = { 1 }; // { dg-error "" "not an aggregate" } + decltype(lam) lam3; // { dg-error "" "deleted default ctor" } + lam3 = lam; // { dg-error "" "deleted assignment op" } +} + +int main() +{ + f(); + g(1); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctors.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctors.C new file mode 100644 index 00000000000..e263145b01d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ctors.C @@ -0,0 +1,18 @@ +// { dg-options -std=c++0x } +// { dg-do run } + +struct A +{ + A() { } + A(A&) { } + A(A&&) { } +}; + +int main() +{ + A a; + auto lam4 = [a]{}; // OK, implicit move ctor + lam4(); + auto lam5 = lam4; // OK, implicit copy ctor + lam5(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C new file mode 100644 index 00000000000..bfe7acab69b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C @@ -0,0 +1,24 @@ +// Testcase for an extension to allow return type deduction when the lambda +// contains more than just a single return-statement. + +// { dg-options -std=c++0x } + +bool b; +template +T f (T t) +{ + return [=] + { + auto i = t+1; + if (b) + return i+1; + else + return i+2; // { dg-error "lambda return type" } + }(); +} + +int main() +{ + if (f(1) != 3) + return 1; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C new file mode 100644 index 00000000000..a236e6d116e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C @@ -0,0 +1,22 @@ +// Test that in pedantic mode, we warn about the extension to allow return +// type deduction when the lambda contains more than just a single +// return-statement. + +// { dg-options "-std=c++0x -pedantic" } + +bool b; +template +T f (T t) +{ + [=] { return t+1; }; // OK + return [=] { + auto i = t+1; + return i+1; // { dg-warning "only statement" } + }(); +} + +int main() +{ + if (f(1) != 3) + return 1; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C new file mode 100644 index 00000000000..9b5ab79837f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C @@ -0,0 +1,27 @@ +// Testcase for an extension to allow return type deduction when the lambda +// contains more than just a single return-statement. + +// { dg-options -std=c++0x } +// { dg-do run } + +bool b; +template +T f (T t) +{ + return [=] { + auto i = t+1; + if (b) + return i+1; + else + return i+1; + }(); +} + +int main() +{ + // Pointless, but well-formed. + [] { return 1; return 2; }(); + + if (f(1) != 3) + return 1; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-neg.C new file mode 100644 index 00000000000..92dee703e71 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-neg.C @@ -0,0 +1,10 @@ +// { dg-options "-std=c++0x" } +#include + +int main() { + int i = 0; + int& r = [&] () { return i; } (); // { dg-error "" "invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce.C new file mode 100644 index 00000000000..0b4f92ec7e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce.C @@ -0,0 +1,29 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } +#include + +int main() { + [] {}; + [] {} (); + [] () {}; + [] () {} (); + [] () { return "lambda"; }; + + int i = 1, j = 2; + [&i, j] () { i = j; } (); + assert(i == 2); + assert(j == 2); + + i = [] () { return 3; } (); + assert(i == 3); + + int k = [&] () { return i; } (); + + []{ return; }; + + int array[] = { 1, 2, 3 }; + int* p = [&] () { return array; } (); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg.C new file mode 100644 index 00000000000..069935823ea --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg.C @@ -0,0 +1,6 @@ +// { dg-options "-std=c++0x -pedantic-errors" } + +int main() +{ + [](int a = 1) { return a; }(); // { dg-error "" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C new file mode 100644 index 00000000000..ea5060d1a3d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-eh.C @@ -0,0 +1,35 @@ +// Test that we properly clean up if we get an exception in the middle of +// constructing the closure object. +// { dg-options -std=c++0x } + +// This test fails because of PR 41449; it isn't a lambda issue. +// { dg-do run { xfail *-*-* } } + +struct A +{ + A() {} + A(const A&) { throw 1; } +}; + +int bs; +struct B +{ + B() { ++bs; } + B(const B&) { ++bs; } + ~B() { --bs; } +}; + +int main() +{ + { + B b1, b2; + A a; + + try + { + [b1, a, b2]{ }; + } + catch(...) {} + } + return bs; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc.C new file mode 100644 index 00000000000..4037331ee37 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-errloc.C @@ -0,0 +1,18 @@ +// Test that error messages about creating the closure object refer to +// the lambda-introducer. +// { dg-options -std=c++0x } + +struct A +{ + A(); + A(const A& a) = delete; // { dg-error "deleted" } +}; + +int main() +{ + A ar[4][3]; + [ar] { }; // { dg-error "3:" } + + A a; + [a] { }; // { dg-error "3:" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-field-names.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-field-names.C new file mode 100644 index 00000000000..b292d889806 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-field-names.C @@ -0,0 +1,21 @@ +// "For each entity captured by copy, an unnamed non-static data member is +// declared in the closure type" -- test that there isn't a member of the +// closure with the same name as the captured variable. + +// { dg-options -std=c++0x } + +template +struct A: public T +{ + A(T t): T(t) { } + int f() { return this->i; } // { dg-error "" "no member named i" } +}; + +int main() +{ + int i = 42; + auto lam = [i]{ }; + lam.i = 24; // { dg-error "" "no member named i" } + A a(lam); + return a.f(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class-neg.C new file mode 100644 index 00000000000..a93857e46af --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class-neg.C @@ -0,0 +1,35 @@ +// { dg-options "-std=c++0x" } + +#include + +class C { + private: + int m_i; + + public: + C() : m_i(-1) { + [] { this; } (); // { dg-error "not captured" } + [this] () -> void { m_i = 0; } (); + assert(m_i == 0); + [this] () -> void { this->m_i = 1; } (); + assert(m_i == 1); + [&] () -> void { m_i = 2; } (); + assert(m_i == 2); + [&] () -> void { this->m_i = 3; } (); + assert(m_i == 3); + [=] () -> void { m_i = 4; } (); // copies 'this' or --copies-m_i--? + assert(m_i == 4); + [=] () -> void { this->m_i = 5; } (); + assert(m_i == 5); + } + +}; + +int main() { + C c; + + [this] () -> void {} (); // { dg-error "use of 'this' in non-member function" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class.C new file mode 100644 index 00000000000..54015fd72f7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-in-class.C @@ -0,0 +1,36 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include + +class C { + private: + int m_i; + + public: + C() : m_i(-1) { + //[] { this; } (); + [this] () -> void { m_i = 0; } (); + assert(m_i == 0); + [this] () -> void { this->m_i = 1; } (); + assert(m_i == 1); + [&] () -> void { m_i = 2; } (); + assert(m_i == 2); + [&] () -> void { this->m_i = 3; } (); + assert(m_i == 3); + [=] () -> void { m_i = 4; } (); // copies 'this' or --copies-m_i--? + assert(m_i == 4); + [=] () -> void { this->m_i = 5; } (); + assert(m_i == 5); + } + +}; + +int main() { + C c; + + //[this] () -> void {} (); // { dg-error: "cannot capture `this' outside of class method" } + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-lookup-neg.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-lookup-neg.C new file mode 100644 index 00000000000..e07e892a1a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-lookup-neg.C @@ -0,0 +1,7 @@ +// Test that we don't crash on a failed lookup. +// { dg-options -std=c++0x } + +int main() +{ + [i]{}; // { dg-error "not declared" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C new file mode 100644 index 00000000000..dc89d2388fb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C @@ -0,0 +1,102 @@ +// Test lambda mangling +// { dg-options "-std=c++0x -fno-inline" } + +template int algo(F fn) { return fn(); } +inline void g(int n) { + int bef(int i = []{ return 1; }()); + // Default arguments of block-extern function declarations + // remain in the context of the encloding function body. + // The closure type is encoded as Z1giEUlvE_. + // The call operator of that type is _ZZ1giENKUlvE_clEv. + +// { dg-final { scan-assembler "_ZZ1giENKUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[ \t\]*_?_ZZ1giENKUlvE_clEv" { target { ! { *-*-darwin* } } } } } + + algo([=]{return n+bef();}); + // The captured entities do not participate in + // and so this closure type has the same as + // the previous one. It encoding is therefore Z1giEUlvE0_ + // and the call operator is _ZZ1giENKUlvE0_clEv. The + // instance of "algo" being called is then + // _Z4algoIZ1giEUlvE0_EiT_. + +// { dg-final { scan-assembler "_Z4algoIZ1giEUlvE0_EiT_" } } +// { dg-final { scan-assembler "_ZZ1giENKUlvE0_clEv" } } + + int i = []{return 1;}(); + +} + +struct S { + void f(int = + // Type: ZN1S1fEiiEd0_UlvE_ + // Operator: _ZZN1S1fEiiEd0_NKUlvE_clEv +// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NKUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[ \t\]*_?_ZZN1S1fEiiEd0_NKUlvE_clEv" { target { ! { *-*-darwin* } } } } } + []{return 1;}() + // Type: ZN1S1fEiiEd0_UlvE0_ + // Operator: _ZZN1S1fEiiEd0_NKUlvE0_clEv +// { dg-final { scan-assembler "_ZZN1S1fEiiEd0_NKUlvE0_clEv" } } + + []{return 2;}(), + int = + // Type: ZN1S1fEiiEd_UlvE_ + // Operator: _ZZN1S1fEiiEd_NKUlvE_clEv +// { dg-final { scan-assembler "_ZZN1S1fEiiEd_NKUlvE_clEv" } } + []{return 3;}()); +}; + +template struct R { + static int x; +}; +template int R::x = []{return 1;}(); +template int R::x; +// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E +// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv +// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[ \t\]*_?_ZNK1RIiE1xMUlvE_clEv" } } + +void bar() +{ + // lambdas in non-vague linkage functions have internal linkage. + // { dg-final { scan-assembler-not "weak\[^\n\r\]*bar\[^\n\r\]*Ul" } } + []{}(); +} + +// lambdas used in non-template, non-class body initializers are internal. +// { dg-final { scan-assembler-not "weak\[^\n\r\]*_ZNKUlv" } } +// { dg-final { scan-assembler-not "weak\[^\n\r\]*variable" } } +int variable = []{return 1;}(); + +// And a template instantiated with such a lambda is also internal. +// { dg-final { scan-assembler-not "weak\[^\n\r\]*algoIUl" } } +int var2 = algo([]{return 1;}); + +// As are lambdas used in non-class-body default arguments. +// { dg-final { scan-assembler-not "weak\[^\n\r\]*function" } } +void function (int i = []{return 1;}()+[]{return 1;}()); + +struct Foo +{ + static int Int; + void Bar(int); +}; + +int Foo::Int = []{return 1;}(); +// Even default arguments for member functions that appear outside the +// class body are internal. +// { dg-final { scan-assembler-not "weak\[^\n\r\]*Foo" } } +void Foo::Bar(int i = []{return 1;}()) {} + +// Even default arguments for function templates. +// { dg-final { scan-assembler-not "weak\[^\n\r\]*fn2\[^\n\r\]*Ulv" } } +template +void fn2 (T t = []{return 1;}()) {} + +int main() +{ + g(42); + S().f(); + function(); + Foo().Bar(); + fn2(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mixed.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mixed.C new file mode 100644 index 00000000000..14c4de9f912 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mixed.C @@ -0,0 +1,13 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } +#include + +int main() { + int i = 1, j = 2; + [&i, j] () mutable -> void { i = 0; j = 0; } (); + assert(i == 0); + assert(j == 2); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable.C new file mode 100644 index 00000000000..7065dfb3f21 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable.C @@ -0,0 +1,16 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } +#include + +int main() { + int i = 1; + const char* s1 = "hello"; + const char* s2 = s1; + [i, s2] () mutable -> void { i = 2; s2 = "world"; } (); + //[i, s2] () -> void { i = 2; s2 = "world"; } (); // { dg-error: "assignment of data-member in read-only structure" } + assert(i == 1); + assert(s1 == s2); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested.C new file mode 100644 index 00000000000..1689865374e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested.C @@ -0,0 +1,52 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include + +int main() { + int i = 1; + + [] (int& i) -> void { + [&] () -> void { + i = 2; + } (); + } (i); + + assert(i == 2); + + [&] () -> void { + [&i] () -> void { + i = 3; + } (); + } (); + + assert(i == 3); + + [&] () -> void { + [&] () -> void { + i = 4; + } (); + } (); + + assert(i == 4); + i = 4; + + [&] () -> void { + [=] () mutable -> void { + i = 5; + } (); + } (); + + assert(i == 4); + + [=] () mutable -> void { + [&] () -> void { + i = 6; + } (); + } (); + + assert(i == 4); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C new file mode 100644 index 00000000000..9c2b1195af3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-non-const.C @@ -0,0 +1,19 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include + +template +void call(F f) { f(); } + +int main() { + call([] () -> void {}); + call([] () mutable -> void {}); + + int i = -1; + call([i] () mutable -> void { i = 0; }); + assert(i == -1); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nop.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nop.C new file mode 100644 index 00000000000..b366ba1b8fa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nop.C @@ -0,0 +1,19 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } +#include + +int main() { + int i = 1, j = 2; + [i, j] () -> void {} (); + assert(i == 1); + assert(j == 2); + [&i, &j] () -> void {} (); + assert(i == 1); + assert(j == 2); + [] (int x) -> void {} (1); + [] (int& x) -> void {} (i); + [] (int x, int y) -> void {} (i, j); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ns-scope.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ns-scope.C new file mode 100644 index 00000000000..cde0c2e5379 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ns-scope.C @@ -0,0 +1,18 @@ +// { dg-options -std=c++0x } +// { dg-do run } + +auto f = [](int i) { return i+1; }; + +int g(int i = [] { return 237; }()) +{ + return i; +} + +int main() +{ + if (f(41) != 42) + return 1; + if (g() != 237) + return 2; + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-pass.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-pass.C new file mode 100644 index 00000000000..a42de294b6e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-pass.C @@ -0,0 +1,27 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include +#include + +template +void call(F f, const A1& arg1) { + f(arg1); +} + +int main() { + int i = 1; + call( + [&i] (int j) -> void { i = j; }, + 2 + ); + assert(i == 2); + + int A[] = {1, 2, 3, 4}; + int sum = 0; + std::for_each(A, A+4, [&sum] (int n) -> void { sum += n; }); + assert(sum == 10); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-recursive.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-recursive.C new file mode 100644 index 00000000000..c3c8008d926 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-recursive.C @@ -0,0 +1,21 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +//#include +#include +#include + +int main() { + + std::function fib = [&fib] (int n) -> int { + //std::cerr << "fib(" << n << ")\n"; + if (n <= 2) return 1; + else return fib(n-1) + fib(n-2); + }; + + assert(fib(5) == 5); + assert(fib(10) == 55); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref-default.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref-default.C new file mode 100644 index 00000000000..342e0aeb2cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref-default.C @@ -0,0 +1,15 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include + +int main() { + int i = 1; + float j = 2.0; + [&] () -> void { i = 3; j = 4.0; } (); + assert(i == 3); + assert(j == 4.0); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref.C new file mode 100644 index 00000000000..34ba263b2e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ref.C @@ -0,0 +1,15 @@ +// { dg-do "run" } +// { dg-options "-std=c++0x" } + +#include + +int main() { + int i = 1; + float j = 2.0; + [&i, &j] () -> void { i = 3; j = 4.0; } (); + assert(i == 3); + assert(j == 4.0); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-std-function.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-std-function.C new file mode 100644 index 00000000000..26c09fdb119 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-std-function.C @@ -0,0 +1,22 @@ +// Test using std::function wrapper. +// { dg-do run } +// { dg-options -std=c++0x } + +#include + +typedef std::function FN; + +template +FN f(T fn) +{ + return [fn]{return fn(2);}; +} + +int main() +{ + auto fn = f([](int i){return i*21;}); + + if (fn() != 42) + return 1; + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template.C new file mode 100644 index 00000000000..b4db3b881d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template.C @@ -0,0 +1,41 @@ +// { dg-options -std=c++0x } +// { dg-do run } + +extern "C" void abort(); + +template +auto apply (T t) -> decltype (t()) +{ + return t(); +} + +template +T f(T t) +{ + T t2 = t; + if (t != [=]()->T { return t; }()) + abort (); + if (t != [=] { return t; }()) + abort (); + if (t != [=] { return t2; }()) + abort (); + if (t != [&] { return t; }()) + abort (); + if (t != apply([=]{return t;})) + abort (); + + int i; + [&] (int a) { return a+i+t; } (0); + [&] (int a) -> decltype(a) { return a+i+t; } (0); + [&] (int a) -> decltype(i) { return a+i+t; } (0); + [&] (int a) -> decltype(t) { return a+i+t; } (0); + [&] (int a) -> decltype(a+i) { return a+i+t; } (0); + [&] (int a) -> decltype(a+t) { return a+i+t; } (0); + [&] (int a) -> decltype(i+t) { return a+i+t; } (0); + [&] (int a) -> decltype(a+i+t) { return a+i+t; } (0); +} + +int main() +{ + f(0xbeef); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this.C new file mode 100644 index 00000000000..ed2747654f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this.C @@ -0,0 +1,13 @@ +// Test that implicit 'this' capture works, but that it's still an rvalue. +// { dg-options -std=c++0x } + +struct A +{ + int i; + void f() + { + [=] { i = 0; }; + [&] { i = 0; }; + [=] { this = 0; }; // { dg-error "lvalue" } + } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-type.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-type.C new file mode 100644 index 00000000000..3b2a2a76a46 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-type.C @@ -0,0 +1,74 @@ +// Every id-expression that is a use (_basic.def.odr_ 3.2) of an entity +// captured by copy is transformed into an access to the corresponding +// unnamed data member of the closure type. +//... +// Every occurrence of decltype((x)) where x is a possibly parenthesized +// id-expression that names an entity of automatic storage duration is +// treated as if x were transformed into an access to a corresponding data +// member of the closure type that would have been declared if x were a use +// of the denoted entity. + +// So, other appearances of 'x' within decltype do not refer to the closure +// member, because they are not "use"s in the sense of 3.2. + +// { dg-options -std=c++0x } + +template +struct same_type; +template +struct same_type { }; + +int main() +{ + int i; + [=] { + same_type(); + same_type(); + i+1; + same_type(); + same_type(); + }; + [=] { + same_type(); + same_type(); + same_type(); + }; + [=] () mutable { + same_type(); + same_type(); + same_type(); + }; + [&] { + same_type(); + same_type(); + same_type(); + }; + [i] { + same_type(); + same_type(); + }; + [&,i] { + same_type(); + same_type(); + }; + [i] () mutable { + same_type(); + same_type(); + }; + [&,i] () mutable { + same_type(); + same_type(); + }; + [&i] { + same_type(); + same_type(); + }; + [=,&i] { + same_type(); + same_type(); + }; + [] { + same_type(); + same_type(); // { dg-error "" "not captured" } + }; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-use.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-use.C new file mode 100644 index 00000000000..b1d6c300cfd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-use.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++0x } + +int main(int argc, char** argv) +{ + int i; + int &ir = i; + const int ci = 0; + const int &cir = ci; + + [] { sizeof (argc); sizeof (i); sizeof (ir); sizeof (ci); sizeof (cir); }; + [] { int ia[ci]; }; +} diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp index 5a835098e25..c61ec21c15a 100644 --- a/gcc/testsuite/lib/prune.exp +++ b/gcc/testsuite/lib/prune.exp @@ -20,7 +20,7 @@ proc prune_gcc_output { text } { #send_user "Before:$text\n" - regsub -all "(^|\n)(\[^\n\]*: )?In ((static member )?function|member|method|(copy )?constructor|destructor|instantiation|program|subroutine|block-data) \[^\n\]*" $text "" text + regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|program|subroutine|block-data)\[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*: instantiated from \[^\n\]*" $text "" text regsub -all "(^|\n) inlined from \[^\n\]*" $text "" text diff --git a/include/ChangeLog.lambda b/include/ChangeLog.lambda new file mode 100644 index 00000000000..6195e348486 --- /dev/null +++ b/include/ChangeLog.lambda @@ -0,0 +1,6 @@ +2009-09-29 Jason Merrill + + * demangle.h (enum demangle_component_type): Add + DEMANGLE_COMPONENT_LAMBDA, DEMANGLE_COMPONENT_DEFAULT_ARG, + DEMANGLE_COMPONENT_UNNAMED_TYPE. + (struct demangle_component): Add s_unary_num. diff --git a/include/demangle.h b/include/demangle.h index 4b3565bfbb8..76fab0a4582 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -381,6 +381,12 @@ enum demangle_component_type DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS, /* Global destructors keyed to name. */ DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS, + /* A lambda closure type. */ + DEMANGLE_COMPONENT_LAMBDA, + /* A default argument scope. */ + DEMANGLE_COMPONENT_DEFAULT_ARG, + /* An unnamed type. */ + DEMANGLE_COMPONENT_UNNAMED_TYPE, /* A pack expansion. */ DEMANGLE_COMPONENT_PACK_EXPANSION }; @@ -494,6 +500,14 @@ struct demangle_component struct demangle_component *right; } s_binary; + struct + { + /* subtree, same place as d_left. */ + struct demangle_component *sub; + /* integer. */ + int num; + } s_unary_num; + } u; }; diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index dd1c1a301fc..03a84798d30 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,14 @@ +2009-09-29 Jason Merrill + + * Makefile.in: Enable demangle target. + * cp-demangle.c (d_lambda, d_unnamed_type, d_make_default_arg): New. + (d_name, d_prefix, d_unqualified_name, d_local_name): Handle lambdas. + (d_parmlist): Factor out from d_bare_function_type. + (d_compact_number): Factor out from d_template_param and d_expression. + (d_append_num): Factor out from d_print_comp. + (d_print_comp, d_print_mod_list): Handle lambdas. + * testsuite/demangle-expected: Add lambda tests. + 2009-09-23 Matthew Gingell * cplus-dem.c (ada_demangle): Ensure demangled is freed. diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in index 5d2adffc7b7..ba24c6db7a7 100644 --- a/libiberty/Makefile.in +++ b/libiberty/Makefile.in @@ -371,10 +371,12 @@ TAGS: $(CFILES) etags `for i in $(CFILES); do echo $(srcdir)/$$i ; done` # The standalone demangler (c++filt) has been moved to binutils. -demangle: +# But make this target work anyway for demangler hacking. +demangle: $(ALL) $(srcdir)/cp-demangle.c @echo "The standalone demangler, now named c++filt, is now" @echo "a part of binutils." - @false + $(CC) @DEFS@ $(CFLAGS) $(CPPFLAGS) -I. -I$(INCDIR) $(HDEFINES) \ + $(srcdir)/cp-demangle.c -DSTANDALONE_DEMANGLER $(TARGETLIB) -o $@ ls: @echo Makefile $(CFILES) diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 2c7296f7eef..43cf34a36cf 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -408,6 +408,10 @@ static struct demangle_component *d_local_name (struct d_info *); static int d_discriminator (struct d_info *); +static struct demangle_component *d_lambda (struct d_info *); + +static struct demangle_component *d_unnamed_type (struct d_info *); + static int d_add_substitution (struct d_info *, struct demangle_component *); @@ -922,6 +926,20 @@ d_make_extended_operator (struct d_info *di, int args, return p; } +static struct demangle_component * +d_make_default_arg (struct d_info *di, int num, + struct demangle_component *sub) +{ + struct demangle_component *p = d_make_empty (di); + if (p) + { + p->type = DEMANGLE_COMPONENT_DEFAULT_ARG; + p->u.s_unary_num.num = num; + p->u.s_unary_num.sub = sub; + } + return p; +} + /* Add a new constructor component. */ static struct demangle_component * @@ -1153,8 +1171,9 @@ d_name (struct d_info *di) return d_local_name (di); case 'L': + case 'U': return d_unqualified_name (di); - + case 'S': { int subst; @@ -1276,6 +1295,7 @@ d_prefix (struct d_info *di) || IS_LOWER (peek) || peek == 'C' || peek == 'D' + || peek == 'U' || peek == 'L') dc = d_unqualified_name (di); else if (peek == 'S') @@ -1291,6 +1311,16 @@ d_prefix (struct d_info *di) dc = d_template_param (di); else if (peek == 'E') return ret; + else if (peek == 'M') + { + /* Initializer scope for a lambda. We don't need to represent + this; the normal code will just treat the variable as a type + scope, which gives appropriate output. */ + if (ret == NULL) + return NULL; + d_advance (di, 1); + continue; + } else return NULL; @@ -1347,6 +1377,18 @@ d_unqualified_name (struct d_info *di) return NULL; return ret; } + else if (peek == 'U') + { + switch (d_peek_next_char (di)) + { + case 'l': + return d_lambda (di); + case 't': + return d_unnamed_type (di); + default: + return NULL; + } + } else return NULL; } @@ -2242,50 +2284,30 @@ d_function_type (struct d_info *di) return ret; } -/* ::= [J]+ */ +/* + */ static struct demangle_component * -d_bare_function_type (struct d_info *di, int has_return_type) +d_parmlist (struct d_info *di) { - struct demangle_component *return_type; struct demangle_component *tl; struct demangle_component **ptl; - char peek; - /* Detect special qualifier indicating that the first argument - is the return type. */ - peek = d_peek_char (di); - if (peek == 'J') - { - d_advance (di, 1); - has_return_type = 1; - } - - return_type = NULL; tl = NULL; ptl = &tl; while (1) { struct demangle_component *type; - peek = d_peek_char (di); + char peek = d_peek_char (di); if (peek == '\0' || peek == 'E') break; type = cplus_demangle_type (di); if (type == NULL) return NULL; - if (has_return_type) - { - return_type = type; - has_return_type = 0; - } - else - { - *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL); - if (*ptl == NULL) - return NULL; - ptl = &d_right (*ptl); - } + *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL); + if (*ptl == NULL) + return NULL; + ptl = &d_right (*ptl); } /* There should be at least one parameter type besides the optional @@ -2300,10 +2322,45 @@ d_bare_function_type (struct d_info *di, int has_return_type) && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID) { di->expansion -= d_left (tl)->u.s_builtin.type->len; - tl = NULL; + d_left (tl) = NULL; } - return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, return_type, tl); + return tl; +} + +/* ::= [J]+ */ + +static struct demangle_component * +d_bare_function_type (struct d_info *di, int has_return_type) +{ + struct demangle_component *return_type; + struct demangle_component *tl; + char peek; + + /* Detect special qualifier indicating that the first argument + is the return type. */ + peek = d_peek_char (di); + if (peek == 'J') + { + d_advance (di, 1); + has_return_type = 1; + } + + if (has_return_type) + { + return_type = cplus_demangle_type (di); + if (return_type == NULL) + return NULL; + } + else + return_type = NULL; + + tl = d_parmlist (di); + if (tl == NULL) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, + return_type, tl); } /* ::= */ @@ -2405,6 +2462,24 @@ d_pointer_to_member_type (struct d_info *di) return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); } +/* _ */ + +static long +d_compact_number (struct d_info *di) +{ + long num; + if (d_peek_char (di) == '_') + num = 0; + else if (d_peek_char (di) == 'n') + return -1; + else + num = d_number (di) + 1; + + if (! d_check_char (di, '_')) + return -1; + return num; +} + /* ::= T_ ::= T <(parameter-2 non-negative) number> _ */ @@ -2417,17 +2492,8 @@ d_template_param (struct d_info *di) if (! d_check_char (di, 'T')) return NULL; - if (d_peek_char (di) == '_') - param = 0; - else - { - param = d_number (di); - if (param < 0) - return NULL; - param += 1; - } - - if (! d_check_char (di, '_')) + param = d_compact_number (di); + if (param < 0) return NULL; ++di->did_subs; @@ -2599,17 +2665,8 @@ d_expression (struct d_info *di) /* Function parameter used in a late-specified return type. */ int index; d_advance (di, 2); - if (d_peek_char (di) == '_') - index = 1; - else - { - index = d_number (di); - if (index < 0) - return NULL; - index += 2; - } - - if (! d_check_char (di, '_')) + index = d_compact_number (di); + if (index < 0) return NULL; return d_make_function_param (di, index); @@ -2802,10 +2859,31 @@ d_local_name (struct d_info *di) else { struct demangle_component *name; + int num = -1; + + if (d_peek_char (di) == 'd') + { + /* Default argument scope: d _. */ + d_advance (di, 1); + num = d_compact_number (di); + if (num < 0) + return NULL; + } name = d_name (di); - if (! d_discriminator (di)) - return NULL; + if (name) + switch (name->type) + { + /* Lambdas and unnamed types have internal discriminators. */ + case DEMANGLE_COMPONENT_LAMBDA: + case DEMANGLE_COMPONENT_UNNAMED_TYPE: + break; + default: + if (! d_discriminator (di)) + return NULL; + } + if (num >= 0) + name = d_make_default_arg (di, num, name); return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name); } } @@ -2829,6 +2907,75 @@ d_discriminator (struct d_info *di) return 1; } +/* ::= Ul E [ ] _ */ + +static struct demangle_component * +d_lambda (struct d_info *di) +{ + struct demangle_component *tl; + struct demangle_component *ret; + int num; + + if (! d_check_char (di, 'U')) + return NULL; + if (! d_check_char (di, 'l')) + return NULL; + + tl = d_parmlist (di); + if (tl == NULL) + return NULL; + + if (! d_check_char (di, 'E')) + return NULL; + + num = d_compact_number (di); + if (num < 0) + return NULL; + + ret = d_make_empty (di); + if (ret) + { + ret->type = DEMANGLE_COMPONENT_LAMBDA; + ret->u.s_unary_num.sub = tl; + ret->u.s_unary_num.num = num; + } + + if (! d_add_substitution (di, ret)) + return NULL; + + return ret; +} + +/* ::= Ut [ ] _ */ + +static struct demangle_component * +d_unnamed_type (struct d_info *di) +{ + struct demangle_component *ret; + long num; + + if (! d_check_char (di, 'U')) + return NULL; + if (! d_check_char (di, 't')) + return NULL; + + num = d_compact_number (di); + if (num < 0) + return NULL; + + ret = d_make_empty (di); + if (ret) + { + ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE; + ret->u.s_number.number = num; + } + + if (! d_add_substitution (di, ret)) + return NULL; + + return ret; +} + /* Add a new substitution. */ static int @@ -3122,6 +3269,14 @@ d_append_string (struct d_print_info *dpi, const char *s) d_append_buffer (dpi, s, strlen (s)); } +static inline void +d_append_num (struct d_print_info *dpi, long l) +{ + char buf[25]; + sprintf (buf,"%ld", l); + d_append_string (dpi, buf); +} + static inline char d_last_char (struct d_print_info *dpi) { @@ -3398,6 +3553,8 @@ d_print_comp (struct d_print_info *dpi, struct demangle_component *local_name; local_name = d_right (typed_name); + if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) + local_name = local_name->u.s_unary_num.sub; while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS || local_name->type == DEMANGLE_COMPONENT_CONST_THIS) @@ -4048,13 +4205,10 @@ d_print_comp (struct d_print_info *dpi, return; case DEMANGLE_COMPONENT_FUNCTION_PARAM: - { - char buf[25]; - d_append_string (dpi, "parm#"); - sprintf(buf,"%ld", dc->u.s_number.number); - d_append_string (dpi, buf); - return; - } + d_append_string (dpi, "{parm#"); + d_append_num (dpi, dc->u.s_number.number + 1); + d_append_char (dpi, '}'); + return; case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: d_append_string (dpi, "global constructors keyed to "); @@ -4066,6 +4220,20 @@ d_print_comp (struct d_print_info *dpi, d_print_comp (dpi, dc->u.s_binary.left); return; + case DEMANGLE_COMPONENT_LAMBDA: + d_append_string (dpi, "{lambda("); + d_print_comp (dpi, dc->u.s_unary_num.sub); + d_append_string (dpi, ")#"); + d_append_num (dpi, dc->u.s_unary_num.num + 1); + d_append_char (dpi, '}'); + return; + + case DEMANGLE_COMPONENT_UNNAMED_TYPE: + d_append_string (dpi, "{unnamed type#"); + d_append_num (dpi, dc->u.s_number.number + 1); + d_append_char (dpi, '}'); + return; + default: d_print_error (dpi); return; @@ -4184,6 +4352,15 @@ d_print_mod_list (struct d_print_info *dpi, d_append_char (dpi, '.'); dc = d_right (mods->mod); + + if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG) + { + d_append_string (dpi, "{default arg#"); + d_append_num (dpi, dc->u.s_unary_num.num + 1); + d_append_string (dpi, "}::"); + dc = dc->u.s_unary_num.sub; + } + while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS || dc->type == DEMANGLE_COMPONENT_CONST_THIS) diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 0c451184fc4..6798154d2f3 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -3885,11 +3885,11 @@ java resource java/util/iso4217.properties # decltype/param placeholder test --format=gnu-v3 _Z3addIidEDTplfp_fp0_ET_T0_ -decltype (parm#1+parm#2) add(int, double) +decltype ({parm#1}+{parm#2}) add(int, double) # decltype/fn call test --format=gnu-v3 _Z4add3IidEDTclL_Z1gEfp_fp0_EET_T0_ -decltype (g(parm#1, parm#2)) add3(int, double) +decltype (g({parm#1}, {parm#2})) add3(int, double) # new (2008) built in types test --format=gnu-v3 _Z1fDfDdDeDhDsDi @@ -3901,12 +3901,28 @@ void f(int*, float*, double*) # '.' test --format=gnu-v3 _Z1hI1AIiEdEDTcldtfp_1gIT0_EEET_S2_ -decltype ((parm#1.(g))()) h, double>(A, double) +decltype (({parm#1}.(g))()) h, double>(A, double) # test for typed function in decltype --format=gnu-v3 _ZN1AIiE1jIiEEDTplfp_clL_Z1xvEEET_ -decltype (parm#1+((x())())) A::j(int) +decltype ({parm#1}+((x())())) A::j(int) # test for expansion of function parameter pack --format=gnu-v3 _Z1gIIidEEDTclL_Z1fEspplfp_Li1EEEDpT_ -decltype (f((parm#1+(1))...)) g(int, double) +decltype (f(({parm#1}+(1))...)) g(int, double) +# lambda tests +--format=gnu-v3 +_ZZ1giENKUlvE_clEv +g(int)::{lambda()#1}::operator()() const +--format=gnu-v3 +_Z4algoIZ1giEUlvE0_EiT_ +int algo(g(int)::{lambda()#2}) +--format=gnu-v3 +_ZZN1S1fEiiEd0_NKUlvE0_clEv +S::f(int, int)::{default arg#2}::{lambda()#2}::operator()() const +--format=gnu-v3 +_ZNK1SIiE1xMUlvE1_clEv +S::x::{lambda()#3}::operator()() const +--format=gnu-v3 +_Z1fN1SUt_E +f(S::{unnamed type#1})