c++: Set CALL_FROM_NEW_OR_DELETE_P on more calls.

We were failing to set the flag on a delete call in a new expression, in a
deleting destructor, and in a coroutine.  Fixed by setting it in the
function that builds the call.

2020-10-02  Jason Merril  <jason@redhat.com>

gcc/cp/ChangeLog:
	* call.c (build_operator_new_call): Set CALL_FROM_NEW_OR_DELETE_P.
	(build_op_delete_call): Likewise.
	* init.c (build_new_1, build_vec_delete_1, build_delete): Not here.
	(build_delete):

gcc/ChangeLog:
	* gimple.h (gimple_call_operator_delete_p): Rename from
	gimple_call_replaceable_operator_delete_p.
	* gimple.c (gimple_call_operator_delete_p): Likewise.
	* tree.h (DECL_IS_REPLACEABLE_OPERATOR_DELETE_P): Remove.
	* tree-ssa-dce.c (mark_all_reaching_defs_necessary_1): Adjust.
	(propagate_necessity): Likewise.
	(eliminate_unnecessary_stmts): Likewise.
	* tree-ssa-structalias.c (find_func_aliases_for_call): Likewise.

gcc/testsuite/ChangeLog:
	* g++.dg/pr94314.C: new/delete no longer omitted.
This commit is contained in:
Jason Merrill 2020-10-02 09:00:49 +02:00 committed by Richard Biener
parent 0b945f959f
commit 4f4ced2882
8 changed files with 33 additions and 31 deletions

View File

@ -4769,7 +4769,16 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
*fn = cand->fn;
/* Build the CALL_EXPR. */
return build_over_call (cand, LOOKUP_NORMAL, complain);
tree ret = build_over_call (cand, LOOKUP_NORMAL, complain);
/* Set this flag for all callers of this function. In addition to
new-expressions, this is called for allocating coroutine state; treat
that as an implicit new-expression. */
tree call = extract_call_expr (ret);
if (TREE_CODE (call) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (call) = 1;
return ret;
}
/* Build a new call to operator(). This may change ARGS. */
@ -6146,7 +6155,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
case VEC_NEW_EXPR:
case VEC_DELETE_EXPR:
case DELETE_EXPR:
/* Use build_op_new_call and build_op_delete_call instead. */
/* Use build_operator_new_call and build_op_delete_call instead. */
gcc_unreachable ();
case CALL_EXPR:
@ -6983,6 +6992,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
if (DECL_DELETED_FN (fn) && alloc_fn)
return NULL_TREE;
tree ret;
if (placement)
{
/* The placement args might not be suitable for overload
@ -6995,7 +7005,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
argarray[i] = CALL_EXPR_ARG (placement, i);
if (!mark_used (fn, complain) && !(complain & tf_error))
return error_mark_node;
return build_cxx_call (fn, nargs, argarray, complain);
ret = build_cxx_call (fn, nargs, argarray, complain);
}
else
{
@ -7013,7 +7023,6 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
complain);
}
tree ret;
releasing_vec args;
args->quick_push (addr);
if (destroying)
@ -7026,8 +7035,18 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
args->quick_push (al);
}
ret = cp_build_function_call_vec (fn, &args, complain);
return ret;
}
/* Set this flag for all callers of this function. In addition to
delete-expressions, this is called for deallocating coroutine state;
treat that as an implicit delete-expression. This is also called for
the delete if the constructor throws in a new-expression, and for a
deleting destructor (which implements a delete-expression). */
tree call = extract_call_expr (ret);
if (TREE_CODE (call) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (call) = 1;
return ret;
}
/* [expr.new]

View File

@ -3433,10 +3433,6 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
}
}
tree alloc_call_expr = extract_call_expr (alloc_call);
if (TREE_CODE (alloc_call_expr) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (alloc_call_expr) = 1;
if (cookie_size)
alloc_call = maybe_wrap_new_for_constexpr (alloc_call, elt_type,
cookie_size);
@ -4145,10 +4141,6 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type,
/*placement=*/NULL_TREE,
/*alloc_fn=*/NULL_TREE,
complain);
tree deallocate_call_expr = extract_call_expr (deallocate_expr);
if (TREE_CODE (deallocate_call_expr) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (deallocate_call_expr) = 1;
}
body = loop;
@ -5073,12 +5065,6 @@ build_delete (location_t loc, tree otype, tree addr,
if (do_delete == error_mark_node)
return error_mark_node;
else if (do_delete)
{
tree do_delete_call_expr = extract_call_expr (do_delete);
if (TREE_CODE (do_delete_call_expr) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (do_delete_call_expr) = 1;
}
if (do_delete && !TREE_SIDE_EFFECTS (expr))
expr = do_delete;

View File

@ -2717,12 +2717,12 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
/* Return true when STMT is operator a replaceable delete call. */
bool
gimple_call_replaceable_operator_delete_p (const gcall *stmt)
gimple_call_operator_delete_p (const gcall *stmt)
{
tree fndecl;
if ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
return DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (fndecl);
return DECL_IS_OPERATOR_DELETE_P (fndecl);
return false;
}

View File

@ -1605,7 +1605,7 @@ extern alias_set_type gimple_get_alias_set (tree);
extern bool gimple_ior_addresses_taken (bitmap, gimple *);
extern bool gimple_builtin_call_types_compatible_p (const gimple *, tree);
extern combined_fn gimple_call_combined_fn (const gimple *);
extern bool gimple_call_replaceable_operator_delete_p (const gcall *);
extern bool gimple_call_operator_delete_p (const gcall *);
extern bool gimple_call_builtin_p (const gimple *);
extern bool gimple_call_builtin_p (const gimple *, enum built_in_class);
extern bool gimple_call_builtin_p (const gimple *, enum built_in_function);

View File

@ -78,5 +78,5 @@ int main(){
return 0;
}
/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 1 "cddce1"} } */
/* { dg-final { scan-tree-dump-not "Deleting : operator delete" "cddce1"} } */
/* { dg-final { scan-tree-dump-not "Deleting : B::operator delete" "cddce1"} } */

View File

@ -612,7 +612,7 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
if (callee != NULL_TREE
&& (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
|| DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (callee))
|| DECL_IS_OPERATOR_DELETE_P (callee))
&& gimple_call_from_new_or_delete (call))
return false;
}
@ -877,7 +877,7 @@ propagate_necessity (bool aggressive)
bool is_delete_operator
= (is_gimple_call (stmt)
&& gimple_call_from_new_or_delete (as_a <gcall *> (stmt))
&& gimple_call_replaceable_operator_delete_p (as_a <gcall *> (stmt)));
&& gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
if (is_delete_operator
|| gimple_call_builtin_p (stmt, BUILT_IN_FREE))
{
@ -975,7 +975,7 @@ propagate_necessity (bool aggressive)
if (callee != NULL_TREE
&& (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
|| DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (callee))
|| DECL_IS_OPERATOR_DELETE_P (callee))
&& gimple_call_from_new_or_delete (call))
continue;
@ -1402,7 +1402,7 @@ eliminate_unnecessary_stmts (void)
&& (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
|| (is_gimple_call (stmt)
&& gimple_call_from_new_or_delete (as_a <gcall *> (stmt))
&& gimple_call_replaceable_operator_delete_p (as_a <gcall *> (stmt)))))
&& gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
{
tree ptr = gimple_call_arg (stmt, 0);
if (TREE_CODE (ptr) == SSA_NAME)

View File

@ -4862,7 +4862,7 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
such operator, then the effects for PTA (in particular
the escaping of the pointer) can be ignored. */
else if (fndecl
&& DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (fndecl)
&& DECL_IS_OPERATOR_DELETE_P (fndecl)
&& gimple_call_from_new_or_delete (t))
;
else

View File

@ -3074,9 +3074,6 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
#define DECL_IS_OPERATOR_DELETE_P(NODE) \
(FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_DELETE)
#define DECL_IS_REPLACEABLE_OPERATOR_DELETE_P(NODE) \
(DECL_IS_OPERATOR_DELETE_P (NODE) && DECL_IS_REPLACEABLE_OPERATOR (NODE))
#define DECL_SET_IS_OPERATOR_DELETE(NODE, VAL) \
set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_DELETE, VAL)