@@ -741,6 +741,22 @@ nonlambda_method_basetype (void)
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
pointer. */
@@ -749,9 +765,6 @@ maybe_add_lambda_conv_op (tree type)
{
bool nested = (current_function_decl != NULL_TREE);
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)
return;
@@ -759,7 +772,7 @@ maybe_add_lambda_conv_op (tree type)
if (processing_template_decl)
return;
- bool generic_lambda_p
+ bool const generic_lambda_p
= (DECL_TEMPLATE_INFO (callop)
&& DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);
@@ -770,63 +783,127 @@ maybe_add_lambda_conv_op (tree type)
return;
}
+ /* Non-template conversion operators are defined directly with build_call_a
+ 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 used as a substitute for the return type,
+ DECLTYPE_CALL is also built in-place. The arguments of DECLTYPE_CALL in
+ the return expression may differ in flags from those in 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;
+ tree decltype_call = 0, call;
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
+ /* 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);
- 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);
+ 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 (FUNCTION_PARAMETER_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
- (call, /*id_expression_or_member_access_p=*/false,
+ (decltype_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 = build_call_a (callop,
+ direct_argvec->length (),
+ direct_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));
+ tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
/* First build up the conversion op. */
- rettype = build_pointer_type (stattype);
- name = mangle_conv_op_name_for_type (rettype);
- thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
- fntype = build_method_type_directly (thistype, rettype, void_list_node);
- fn = convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
+ tree rettype = build_pointer_type (stattype);
+ tree name = mangle_conv_op_name_for_type (rettype);
+ tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+ tree fntype = build_method_type_directly (thistype, rettype, void_list_node);
+ tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
+ tree fn = convfn;
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
@@ -861,7 +938,8 @@ maybe_add_lambda_conv_op (tree type)
/* Now build up the thunk to be returned. */
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);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
&& DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
@@ -875,7 +953,7 @@ maybe_add_lambda_conv_op (tree type)
DECL_DECLARED_INLINE_P (fn) = 1;
DECL_STATIC_FUNCTION_P (fn) = 1;
DECL_ARGUMENTS (fn) = fn_args;
- for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+ for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
{
/* Avoid duplicate -Wshadow warnings. */
DECL_NAME (arg) = NULL_TREE;
@@ -907,8 +985,8 @@ maybe_add_lambda_conv_op (tree type)
((symtab_node) cgraph_get_create_node (statfn),
(symtab_node) cgraph_get_create_node (callop));
}
- body = begin_function_body ();
- compound_stmt = begin_compound_stmt (0);
+ tree body = begin_function_body ();
+ tree compound_stmt = begin_compound_stmt (0);
call = convert_from_reference (call);
finish_return_stmt (call);