--- gcc/cp/lambda.c | 77 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 20 deletions(-)
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 98a7925..cf662bb 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -759,12 +759,9 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; - if (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT - (DECL_TI_TEMPLATE (callop)) == callop) - { - warning (0, "Conversion of a generic lambda to a function pointer is not currently implemented."); - return; - } + bool generic_lambda_p + = DECL_TEMPLATE_INFO (callop) + && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop; if (DECL_INITIAL (callop) == NULL_TREE) { @@ -773,7 +770,38 @@ 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 it's 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, 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; + } + } + + stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); /* First build up the conversion op. */ @@ -801,6 +829,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 @@ -827,8 +858,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; @@ -837,6 +868,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) @@ -860,19 +894,22 @@ 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)) + if (!generic_lambda_p) { - mark_exp_read (arg); - vec_safe_push (argvec, arg); + 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 = 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); -- 1.8.3