aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/call.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r--gcc/cp/call.c71
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;
}