diff options
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r-- | gcc/cp/call.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index b0c6370..3dac31a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -289,6 +289,9 @@ build_addr_func (tree function, tsubst_flags_t complain) } function = build_address (function); } + else if (TREE_CODE (function) == FUNCTION_DECL + && DECL_IMMEDIATE_FUNCTION_P (function)) + function = build_address (function); else function = decay_conversion (function, complain, /*reject_builtin=*/false); @@ -8145,6 +8148,40 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) addr, nargs, argarray); if (TREE_THIS_VOLATILE (fn) && cfun) current_function_returns_abnormally = 1; + if (TREE_CODE (fn) == FUNCTION_DECL + && DECL_IMMEDIATE_FUNCTION_P (fn) + && (current_function_decl == NULL_TREE + || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) + && (current_binding_level->kind != sk_function_parms + || !current_binding_level->immediate_fn_ctx_p)) + { + tree obj_arg = NULL_TREE, exprimm = expr; + if (DECL_CONSTRUCTOR_P (fn)) + obj_arg = first_arg; + if (obj_arg + && is_dummy_object (obj_arg) + && !type_dependent_expression_p (obj_arg)) + { + exprimm = build_cplus_new (DECL_CONTEXT (fn), expr, complain); + obj_arg = NULL_TREE; + } + /* Look through *(const T *)&obj. */ + else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF) + { + tree addr = TREE_OPERAND (obj_arg, 0); + STRIP_NOPS (addr); + if (TREE_CODE (addr) == ADDR_EXPR) + { + tree typeo = TREE_TYPE (obj_arg); + tree typei = TREE_TYPE (TREE_OPERAND (addr, 0)); + if (same_type_ignoring_top_level_qualifiers_p (typeo, typei)) + obj_arg = TREE_OPERAND (addr, 0); + } + } + fold_non_dependent_expr (exprimm, complain, + /*manifestly_const_eval=*/true, + obj_arg); + } return convert_from_reference (expr); } @@ -8744,6 +8781,40 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) if (TREE_CODE (c) == CALL_EXPR) TREE_NO_WARNING (c) = 1; } + if (TREE_CODE (fn) == ADDR_EXPR) + { + tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0)); + if (TREE_CODE (fndecl) == FUNCTION_DECL + && DECL_IMMEDIATE_FUNCTION_P (fndecl) + && (current_function_decl == NULL_TREE + || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) + && (current_binding_level->kind != sk_function_parms + || !current_binding_level->immediate_fn_ctx_p)) + { + tree obj_arg = NULL_TREE; + if (DECL_CONSTRUCTOR_P (fndecl)) + obj_arg = cand->first_arg ? cand->first_arg : (*args)[0]; + if (obj_arg && is_dummy_object (obj_arg)) + { + call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain); + obj_arg = NULL_TREE; + } + /* Look through *(const T *)&obj. */ + else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF) + { + tree addr = TREE_OPERAND (obj_arg, 0); + STRIP_NOPS (addr); + if (TREE_CODE (addr) == ADDR_EXPR) + { + tree typeo = TREE_TYPE (obj_arg); + tree typei = TREE_TYPE (TREE_OPERAND (addr, 0)); + if (same_type_ignoring_top_level_qualifiers_p (typeo, typei)) + obj_arg = TREE_OPERAND (addr, 0); + } + } + call = cxx_constant_value (call, obj_arg); + } + } return call; } |