This only supports the explicit template parameter syntax and does not correctly support conversion to static ptr-to-function for generic stateless lambdas. --- gcc/cp/mangle.c | 2 ++ gcc/cp/parser.c | 43 +++++++++++++++++++++++++++++++++++++++++-- gcc/cp/semantics.c | 24 ++++++++++++++++++++---- 3 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 8da62b5..4d4c0fd 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1438,6 +1438,8 @@ write_closure_type_name (const tree type) MANGLE_TRACE_TREE ("closure-type-name", type); write_string ("Ul"); + if (TREE_CODE (fn) == TEMPLATE_DECL) // XXX: should we bother mangling generic lambdas? + fn = DECL_TEMPLATE_RESULT (fn); write_method_parms (parms, /*method_p=*/1, fn); write_char ('E'); write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 319da21..407dca3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8668,6 +8668,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) /* Parse the (optional) middle of a lambda expression. lambda-declarator: + < template-parameter-list [opt] > ( parameter-declaration-clause [opt] ) attribute-specifier [opt] mutable [opt] @@ -8687,10 +8688,26 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) tree param_list = void_list_node; tree attributes = NULL_TREE; tree exception_spec = NULL_TREE; + tree template_param_list = NULL_TREE; tree t; - /* The lambda-declarator is optional, but must begin with an opening - parenthesis if present. */ + /* The template-parameter-list is optional, but must begin with + an opening angle if present. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)) + { + cp_lexer_consume_token (parser->lexer); + + template_param_list = cp_parser_template_parameter_list (parser); + + cp_parser_skip_to_end_of_template_parameter_list (parser); + + /* We just processed one more parameter list. */ + ++parser->num_template_parameter_lists; + } + + /* The parameter-declaration-clause is optional (unless + template-parameter-list was given), 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); @@ -8736,6 +8753,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) leave_scope (); } + else if (template_param_list != NULL_TREE) // generate diagnostic + cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); /* Create the function call operator. @@ -8779,6 +8798,23 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) DECL_ARTIFICIAL (fco) = 1; /* Give the object parameter a different name. */ DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure"); + if (template_param_list != NULL_TREE) + { + tree saved_current_function_decl = current_function_decl; + + /* Clear current function decl to allow check_member_template + to pass. Currently it rejects templates inside functions. + Couldn't figure out a clean way to test for lambda inside + check_member_template. */ + current_function_decl = NULL_TREE; + fco = finish_member_template_decl (fco); + current_function_decl = saved_current_function_decl; + + --parser->num_template_parameter_lists; + + finish_template_decl (template_param_list); + + } } finish_member_declaration (fco); @@ -8822,6 +8858,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) tree compound_stmt; tree cap; + if (TREE_CODE (fco) == TEMPLATE_DECL) + fco = DECL_TEMPLATE_RESULT (fco); + /* Let the front end know that we are going to be defining this function. */ start_preparsed_function (fco, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b5c3b0a..db5ba7b 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9135,7 +9135,7 @@ lambda_function (tree lambda) /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) - lambda = BASELINK_FUNCTIONS (lambda); + lambda = OVL_CURRENT (BASELINK_FUNCTIONS (lambda)); return lambda; } @@ -9381,6 +9381,8 @@ build_capture_proxy (tree member) closure = DECL_CONTEXT (member); fn = lambda_function (closure); + if (TREE_CODE (fn) == TEMPLATE_DECL) + fn = DECL_TEMPLATE_RESULT (fn); lam = CLASSTYPE_LAMBDA_EXPR (closure); /* The proxy variable forwards to the capture field. */ @@ -9795,7 +9797,8 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; - if (DECL_INITIAL (callop) == NULL_TREE) + if (TREE_CODE (callop) != TEMPLATE_DECL + && DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ gcc_assert (errorcount || sorrycount); @@ -9830,6 +9833,10 @@ maybe_add_lambda_conv_op (tree type) if (nested) DECL_INTERFACE_KNOWN (fn) = 1; + // FIXME: generalize/respell add_inherited_template_parms + if (TREE_CODE (callop) == TEMPLATE_DECL) + fn = add_inherited_template_parms (fn, callop); + add_method (type, fn, NULL_TREE); /* Generic thunk code fails for varargs; we'll complain in mark_used if @@ -9856,7 +9863,11 @@ maybe_add_lambda_conv_op (tree type) DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; DECL_STATIC_FUNCTION_P (fn) = 1; - DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); + if (TREE_CODE (callop) == TEMPLATE_DECL) + DECL_ARGUMENTS (fn) = + copy_list (DECL_CHAIN (DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (callop)))); + else + DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg)) { /* Avoid duplicate -Wshadow warnings. */ @@ -9866,6 +9877,11 @@ maybe_add_lambda_conv_op (tree type) if (nested) DECL_INTERFACE_KNOWN (fn) = 1; + // FIXME: refactor/respell add_inherited_template_parms... it is + // FIXME: functionally what we want here + if (TREE_CODE (callop) == TEMPLATE_DECL) + fn = add_inherited_template_parms (fn, callop); + add_method (type, fn, NULL_TREE); if (nested) @@ -9889,7 +9905,7 @@ maybe_add_lambda_conv_op (tree type) body = begin_function_body (); compound_stmt = begin_compound_stmt (0); - arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), + arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (statfn)), null_pointer_node); argvec = make_tree_vector (); argvec->quick_push (arg); -- 1.8.3