Commit 6a8b219b by Adam Butcher

Support lambda templates.

	* parser.c (cp_parser_lambda_declarator_opt): Accept template parameter
	list with std=c++1y or std=gnu++1y.
	(cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call
	operator template to avoid adding template result to symbol table.
	* lambda.c (lambda_function): Return template result if call operator is
	a template.
	(maybe_add_lambda_conv_op): Move declarations to point of use.  Refactor
	operator call building in order to support conversion of a non-capturing
	lambda template to a function pointer with help from ...
	(prepare_op_call): ... this new function.
	* decl2.c (check_member_template): Don't reject lambda call operator
	template in local [lambda] class.
	* pt.c (instantiate_class_template_1): Don't instantiate lambda call
	operator template when instantiating lambda class.

From-SVN: r202611
parent ff63a2f4
...@@ -502,8 +502,9 @@ check_member_template (tree tmpl) ...@@ -502,8 +502,9 @@ check_member_template (tree tmpl)
|| (TREE_CODE (decl) == TYPE_DECL || (TREE_CODE (decl) == TYPE_DECL
&& MAYBE_CLASS_TYPE_P (TREE_TYPE (decl)))) && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))))
{ {
/* The parser rejects template declarations in local classes. */ /* The parser rejects template declarations in local classes
gcc_assert (!current_function_decl); (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. */ /* The parser rejects any use of virtual in a function template. */
gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL
&& DECL_VIRTUAL_P (decl))); && DECL_VIRTUAL_P (decl)));
......
...@@ -196,7 +196,7 @@ lambda_function (tree lambda) ...@@ -196,7 +196,7 @@ lambda_function (tree lambda)
/*protect=*/0, /*want_type=*/false, /*protect=*/0, /*want_type=*/false,
tf_warning_or_error); tf_warning_or_error);
if (lambda) if (lambda)
lambda = BASELINK_FUNCTIONS (lambda); lambda = STRIP_TEMPLATE (get_first_fn (lambda));
return lambda; return lambda;
} }
...@@ -775,6 +775,22 @@ nonlambda_method_basetype (void) ...@@ -775,6 +775,22 @@ nonlambda_method_basetype (void)
return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); return TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
} }
/* Helper function for maybe_add_lambda_conv_op; build a CALL_EXPR with
indicated FN and NARGS, but do not initialize the return type or any of the
argument slots. */
static tree
prepare_op_call (tree fn, int nargs)
{
tree t;
t = build_vl_exp (CALL_EXPR, nargs + 3);
CALL_EXPR_FN (t) = fn;
CALL_EXPR_STATIC_CHAIN (t) = NULL;
return t;
}
/* If the closure TYPE has a static op(), also add a conversion to function /* If the closure TYPE has a static op(), also add a conversion to function
pointer. */ pointer. */
...@@ -783,9 +799,6 @@ maybe_add_lambda_conv_op (tree type) ...@@ -783,9 +799,6 @@ maybe_add_lambda_conv_op (tree type)
{ {
bool nested = (current_function_decl != NULL_TREE); bool nested = (current_function_decl != NULL_TREE);
tree callop = lambda_function (type); tree callop = lambda_function (type);
tree rettype, name, fntype, fn, body, compound_stmt;
tree thistype, stattype, statfn, convfn, call, arg;
vec<tree, va_gc> *argvec;
if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
return; return;
...@@ -793,6 +806,10 @@ maybe_add_lambda_conv_op (tree type) ...@@ -793,6 +806,10 @@ maybe_add_lambda_conv_op (tree type)
if (processing_template_decl) if (processing_template_decl)
return; return;
bool const generic_lambda_p
= (DECL_TEMPLATE_INFO (callop)
&& DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);
if (DECL_INITIAL (callop) == NULL_TREE) if (DECL_INITIAL (callop) == NULL_TREE)
{ {
/* If the op() wasn't instantiated due to errors, give up. */ /* If the op() wasn't instantiated due to errors, give up. */
...@@ -800,16 +817,124 @@ maybe_add_lambda_conv_op (tree type) ...@@ -800,16 +817,124 @@ maybe_add_lambda_conv_op (tree type)
return; return;
} }
stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)), /* Non-template conversion operators are defined directly with build_call_a
FUNCTION_ARG_CHAIN (callop)); and using DIRECT_ARGVEC for arguments (including 'this'). Templates are
deferred and the CALL is built in-place. In the case of a deduced return
call op, the decltype expression, DECLTYPE_CALL, used as a substitute for
the return type is also built in-place. The arguments of DECLTYPE_CALL in
the return expression may differ in flags from those in the body CALL. In
particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in
the body CALL, but not in DECLTYPE_CALL. */
vec<tree, va_gc> *direct_argvec = 0;
tree decltype_call = 0, call = 0;
tree fn_result = TREE_TYPE (TREE_TYPE (callop));
if (generic_lambda_p)
{
/* Prepare the dependent member call for the static member function
'_FUN' and, potentially, prepare another call to be used in a decltype
return expression for a deduced return call op to allow for simple
implementation of the conversion operator. */
tree instance = build_nop (type, null_pointer_node);
tree objfn = build_min (COMPONENT_REF, NULL_TREE,
instance, DECL_NAME (callop), NULL_TREE);
int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;
call = prepare_op_call (objfn, nargs);
if (type_uses_auto (fn_result))
decltype_call = prepare_op_call (objfn, nargs);
}
else
{
direct_argvec = make_tree_vector ();
direct_argvec->quick_push (build1 (NOP_EXPR,
TREE_TYPE (DECL_ARGUMENTS (callop)),
null_pointer_node));
}
/* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to
declare the static member function "_FUN" below. For each arg append to
DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated
call args (for the template case). If a parameter pack is found, expand
it, flagging it as PACK_EXPANSION_LOCAL_P for the body call. */
tree fn_args = NULL_TREE;
{
int ix = 0;
tree src = DECL_CHAIN (DECL_ARGUMENTS (callop));
tree tgt;
while (src)
{
tree new_node = copy_node (src);
if (!fn_args)
fn_args = tgt = new_node;
else
{
TREE_CHAIN (tgt) = new_node;
tgt = new_node;
}
mark_exp_read (tgt);
if (generic_lambda_p)
{
if (DECL_PACK_P (tgt))
{
tree a = make_pack_expansion (tgt);
if (decltype_call)
CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
PACK_EXPANSION_LOCAL_P (a) = true;
CALL_EXPR_ARG (call, ix) = a;
}
else
{
tree a = convert_from_reference (tgt);
CALL_EXPR_ARG (call, ix) = a;
if (decltype_call)
CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
}
++ix;
}
else
vec_safe_push (direct_argvec, tgt);
src = TREE_CHAIN (src);
}
}
if (generic_lambda_p)
{
if (decltype_call)
{
++processing_template_decl;
fn_result = finish_decltype_type
(decltype_call, /*id_expression_or_member_access_p=*/false,
tf_warning_or_error);
--processing_template_decl;
}
}
else
call = build_call_a (callop,
direct_argvec->length (),
direct_argvec->address ());
CALL_FROM_THUNK_P (call) = 1;
tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
/* First build up the conversion op. */ /* First build up the conversion op. */
rettype = build_pointer_type (stattype); tree rettype = build_pointer_type (stattype);
name = mangle_conv_op_name_for_type (rettype); tree name = mangle_conv_op_name_for_type (rettype);
thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST); tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
fntype = build_method_type_directly (thistype, rettype, void_list_node); tree fntype = build_method_type_directly (thistype, rettype, void_list_node);
fn = convfn = build_lang_decl (FUNCTION_DECL, name, fntype); tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
tree fn = convfn;
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
...@@ -828,6 +953,9 @@ maybe_add_lambda_conv_op (tree type) ...@@ -828,6 +953,9 @@ maybe_add_lambda_conv_op (tree type)
if (nested) if (nested)
DECL_INTERFACE_KNOWN (fn) = 1; 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); add_method (type, fn, NULL_TREE);
/* Generic thunk code fails for varargs; we'll complain in mark_used if /* Generic thunk code fails for varargs; we'll complain in mark_used if
...@@ -841,7 +969,8 @@ maybe_add_lambda_conv_op (tree type) ...@@ -841,7 +969,8 @@ maybe_add_lambda_conv_op (tree type)
/* Now build up the thunk to be returned. */ /* Now build up the thunk to be returned. */
name = get_identifier ("_FUN"); name = get_identifier ("_FUN");
fn = statfn = build_lang_decl (FUNCTION_DECL, name, stattype); tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
fn = statfn;
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
&& DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
...@@ -854,8 +983,8 @@ maybe_add_lambda_conv_op (tree type) ...@@ -854,8 +983,8 @@ maybe_add_lambda_conv_op (tree type)
DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1;
DECL_STATIC_FUNCTION_P (fn) = 1; DECL_STATIC_FUNCTION_P (fn) = 1;
DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); DECL_ARGUMENTS (fn) = fn_args;
for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg)) for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
{ {
/* Avoid duplicate -Wshadow warnings. */ /* Avoid duplicate -Wshadow warnings. */
DECL_NAME (arg) = NULL_TREE; DECL_NAME (arg) = NULL_TREE;
...@@ -864,6 +993,9 @@ maybe_add_lambda_conv_op (tree type) ...@@ -864,6 +993,9 @@ maybe_add_lambda_conv_op (tree type)
if (nested) if (nested)
DECL_INTERFACE_KNOWN (fn) = 1; 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); add_method (type, fn, NULL_TREE);
if (nested) if (nested)
...@@ -884,29 +1016,23 @@ maybe_add_lambda_conv_op (tree type) ...@@ -884,29 +1016,23 @@ maybe_add_lambda_conv_op (tree type)
((symtab_node) cgraph_get_create_node (statfn), ((symtab_node) cgraph_get_create_node (statfn),
(symtab_node) cgraph_get_create_node (callop)); (symtab_node) cgraph_get_create_node (callop));
} }
body = begin_function_body (); tree body = begin_function_body ();
compound_stmt = begin_compound_stmt (0); tree compound_stmt = begin_compound_stmt (0);
if (!generic_lambda_p)
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); set_flags_from_callee (call);
vec_safe_push (argvec, arg); if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
} }
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); call = convert_from_reference (call);
finish_return_stmt (call); finish_return_stmt (call);
finish_compound_stmt (compound_stmt); finish_compound_stmt (compound_stmt);
finish_function_body (body); 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. */ /* Generate the body of the conversion op. */
...@@ -922,7 +1048,9 @@ maybe_add_lambda_conv_op (tree type) ...@@ -922,7 +1048,9 @@ maybe_add_lambda_conv_op (tree type)
finish_compound_stmt (compound_stmt); finish_compound_stmt (compound_stmt);
finish_function_body (body); 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) if (nested)
pop_function_context (); pop_function_context ();
......
...@@ -8791,6 +8791,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) ...@@ -8791,6 +8791,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
/* Parse the (optional) middle of a lambda expression. /* Parse the (optional) middle of a lambda expression.
lambda-declarator: lambda-declarator:
< template-parameter-list [opt] >
( parameter-declaration-clause [opt] ) ( parameter-declaration-clause [opt] )
attribute-specifier [opt] attribute-specifier [opt]
mutable [opt] mutable [opt]
...@@ -8810,9 +8811,30 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) ...@@ -8810,9 +8811,30 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
tree param_list = void_list_node; tree param_list = void_list_node;
tree attributes = NULL_TREE; tree attributes = NULL_TREE;
tree exception_spec = NULL_TREE; tree exception_spec = NULL_TREE;
tree template_param_list = NULL_TREE;
/* The lambda-declarator is optional, but must begin with an opening /* The template-parameter-list is optional, but must begin with
parenthesis if present. */ an opening angle if present. */
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
if (cxx_dialect < cxx1y)
pedwarn (parser->lexer->next_token->location, 0,
"lambda templates are only available with "
"-std=c++1y or -std=gnu++1y");
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)) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{ {
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
...@@ -8855,6 +8877,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) ...@@ -8855,6 +8877,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
trailing-return-type in case of decltype. */ trailing-return-type in case of decltype. */
pop_bindings_and_leave_scope (); pop_bindings_and_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. /* Create the function call operator.
...@@ -8898,6 +8922,12 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) ...@@ -8898,6 +8922,12 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
DECL_ARTIFICIAL (fco) = 1; DECL_ARTIFICIAL (fco) = 1;
/* Give the object parameter a different name. */ /* Give the object parameter a different name. */
DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure"); 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); finish_member_declaration (fco);
...@@ -9020,7 +9050,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) ...@@ -9020,7 +9050,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
finish_lambda_scope (); finish_lambda_scope ();
/* Finish the function and generate code for it if necessary. */ /* 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; parser->local_variables_forbidden_p = local_variables_forbidden_p;
......
...@@ -9142,7 +9142,9 @@ instantiate_class_template_1 (tree type) ...@@ -9142,7 +9142,9 @@ instantiate_class_template_1 (tree type)
tree decl = lambda_function (type); tree decl = lambda_function (type);
if (decl) 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 /* We need to instantiate the capture list from the template
after we've instantiated the closure members, but before we after we've instantiated the closure members, but before we
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment