+/* 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 GTY(()) tree lambda_scope;
+static GTY(()) 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);
+}
+
+/* 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);
+
+ /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
+ determine_visibility (TYPE_NAME (type));
+
+ {
+ /* 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)
+ {
+ tree field = TREE_PURPOSE (elt);
+ char *buf;
+
+ next = TREE_CHAIN (elt);
+ TREE_CHAIN (elt) = newlist;
+ newlist = elt;
+
+ /* 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. */
+ if (field == LAMBDA_EXPR_THIS_CAPTURE (lambda_expr))
+ /* The 'this' capture already starts with __. */
+ continue;
+
+ 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);
+ }
+ LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) = newlist;
+ }
+
+ maybe_add_lambda_conv_op (type);
+
+ 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;
+ bool explicit_init_p = false;
+
+ 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,
+ explicit_init_p);
+ 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);
+ break;
+ }
+
+ /* 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);
+ explicit_init_p = true;
+ }
+ 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,
+ explicit_init_p);
+ }
+
+ 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 = TYPE_UNQUALIFIED;
+ if (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) == NULL_TREE
+ && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) == CPLD_NONE)
+ {
+ /* A lambda with no captures has a static op() and a conversion op
+ to function type. */
+ if (LAMBDA_EXPR_MUTABLE_P (lambda_expr))
+ error ("lambda expression with no captures declared mutable");
+ return_type_specs.storage_class = sc_static;
+ }
+ else if (!LAMBDA_EXPR_MUTABLE_P (lambda_expr))
+ quals = 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, "%<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();
+}
+