@@ -507,8 +507,9 @@ check_member_template (tree tmpl)
|| (TREE_CODE (decl) == TYPE_DECL
&& MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))))
{
- /* The parser rejects template declarations in local classes. */
- gcc_assert (!current_function_decl);
+ /* The parser rejects template declarations in local classes
+ (with the exception of generic lambdas). */
+ gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl));
/* The parser rejects any use of virtual in a function template. */
gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL
&& DECL_VIRTUAL_P (decl)));
@@ -196,7 +196,7 @@ lambda_function (tree lambda)
/*protect=*/0, /*want_type=*/false,
tf_warning_or_error);
if (lambda)
- lambda = BASELINK_FUNCTIONS (lambda);
+ lambda = STRIP_TEMPLATE (get_first_fn (lambda));
return lambda;
}
@@ -759,6 +759,10 @@ maybe_add_lambda_conv_op (tree type)
if (processing_template_decl)
return;
+ bool generic_lambda_p
+ = (DECL_TEMPLATE_INFO (callop)
+ && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);
+
if (DECL_INITIAL (callop) == NULL_TREE)
{
/* If the op() wasn't instantiated due to errors, give up. */
@@ -766,7 +770,54 @@ maybe_add_lambda_conv_op (tree type)
return;
}
- stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)),
+ tree fn_result = TREE_TYPE (TREE_TYPE (callop));
+ tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
+
+ if (generic_lambda_p)
+ {
+ /* Construct the dependent member call for the static member function
+ '_FUN' and remove 'auto' from its return type to allow for simple
+ implementation of the conversion operator. */
+
+ tree instance = build_nop (type, null_pointer_node);
+ argvec = make_tree_vector ();
+ for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+ {
+ mark_exp_read (arg);
+ vec_safe_push (argvec, convert_from_reference (arg));
+ }
+
+ tree objfn = build_min (COMPONENT_REF, NULL_TREE,
+ instance, DECL_NAME (callop), NULL_TREE);
+ call = build_nt_call_vec (objfn, argvec);
+
+ if (type_uses_auto (fn_result))
+ {
+ ++processing_template_decl;
+ fn_result = finish_decltype_type
+ (call, /*id_expression_or_member_access_p=*/false,
+ tf_warning_or_error);
+ --processing_template_decl;
+ }
+ }
+ else
+ {
+ arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
+ null_pointer_node);
+ argvec = make_tree_vector ();
+ argvec->quick_push (arg);
+ for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+ {
+ mark_exp_read (arg);
+ vec_safe_push (argvec, arg);
+ }
+ call = build_call_a (callop, argvec->length (), argvec->address ());
+ CALL_FROM_THUNK_P (call) = 1;
+ if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
+ call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
+ }
+
+ stattype = build_function_type (fn_result,
FUNCTION_ARG_CHAIN (callop));
/* First build up the conversion op. */
@@ -794,6 +845,9 @@ maybe_add_lambda_conv_op (tree type)
if (nested)
DECL_INTERFACE_KNOWN (fn) = 1;
+ if (generic_lambda_p)
+ fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
+
add_method (type, fn, NULL_TREE);
/* Generic thunk code fails for varargs; we'll complain in mark_used if
@@ -820,8 +874,8 @@ 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)));
- for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg))
+ DECL_ARGUMENTS (fn) = fn_args;
+ for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
{
/* Avoid duplicate -Wshadow warnings. */
DECL_NAME (arg) = NULL_TREE;
@@ -830,6 +884,9 @@ maybe_add_lambda_conv_op (tree type)
if (nested)
DECL_INTERFACE_KNOWN (fn) = 1;
+ if (generic_lambda_p)
+ fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
+
add_method (type, fn, NULL_TREE);
if (nested)
@@ -852,27 +909,15 @@ 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)),
- null_pointer_node);
- argvec = make_tree_vector ();
- argvec->quick_push (arg);
- for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
- {
- mark_exp_read (arg);
- vec_safe_push (argvec, arg);
- }
- call = build_call_a (callop, argvec->length (), argvec->address ());
- CALL_FROM_THUNK_P (call) = 1;
- if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
- call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
call = convert_from_reference (call);
finish_return_stmt (call);
finish_compound_stmt (compound_stmt);
finish_function_body (body);
- expand_or_defer_fn (finish_function (2));
+ fn = finish_function (/*inline*/2);
+ if (!generic_lambda_p)
+ expand_or_defer_fn (fn);
/* Generate the body of the conversion op. */
@@ -888,7 +933,9 @@ maybe_add_lambda_conv_op (tree type)
finish_compound_stmt (compound_stmt);
finish_function_body (body);
- expand_or_defer_fn (finish_function (2));
+ fn = finish_function (/*inline*/2);
+ if (!generic_lambda_p)
+ expand_or_defer_fn (fn);
if (nested)
pop_function_context ();
@@ -8790,6 +8790,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]
@@ -8809,10 +8810,31 @@ 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);
+
+ if (cxx_dialect < cxx1y || flag_iso)
+ cp_parser_error (parser,
+ "lambda templates are only available with "
+ "-std=gnu++1y");
+
+ 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);
@@ -8858,6 +8880,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.
@@ -8901,6 +8925,12 @@ 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)
+ {
+ fco = finish_member_template_decl (fco);
+ finish_template_decl (template_param_list);
+ --parser->num_template_parameter_lists;
+ }
}
finish_member_declaration (fco);
@@ -9023,7 +9053,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
finish_lambda_scope ();
/* Finish the function and generate code for it if necessary. */
- expand_or_defer_fn (finish_function (/*inline*/2));
+ tree fn = finish_function (/*inline*/2);
+
+ /* Only expand if the call op is not a template. */
+ if (!DECL_TEMPLATE_INFO (fco))
+ expand_or_defer_fn (fn);
}
parser->local_variables_forbidden_p = local_variables_forbidden_p;
@@ -9101,7 +9101,9 @@ instantiate_class_template_1 (tree type)
tree decl = lambda_function (type);
if (decl)
{
- instantiate_decl (decl, false, false);
+ if (!DECL_TEMPLATE_INFO (decl) || DECL_TEMPLATE_RESULT
+ (DECL_TI_TEMPLATE (decl)) != decl)
+ instantiate_decl (decl, false, false);
/* We need to instantiate the capture list from the template
after we've instantiated the closure members, but before we