commit 592714921200fa07e1a9de230522804a82bdb5c9 Author: Jason Merrill Date: Thu Oct 1 11:21:57 2020 -0400 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. 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/testsuite/ChangeLog: * g++.dg/pr94314.C: new/delete no longer omitted. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index d67e8fe2b28..bd662518958 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4769,7 +4769,16 @@ build_operator_new_call (tree fnname, vec **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] diff --git a/gcc/cp/init.c b/gcc/cp/init.c index e84e985492d..00fff3f7327 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3433,10 +3433,6 @@ build_new_1 (vec **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; diff --git a/gcc/testsuite/g++.dg/pr94314.C b/gcc/testsuite/g++.dg/pr94314.C index 4e5ae122e9f..72467127fea 100644 --- a/gcc/testsuite/g++.dg/pr94314.C +++ b/gcc/testsuite/g++.dg/pr94314.C @@ -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"} } */ commit 379fc0feec0b8051a8ef12d7f4d636ec0a990ec0 Author: Jason Merrill Date: Thu Oct 1 16:39:03 2020 -0400 tree-ssa-dce: Ignore whether an operator delete is replaceable. Now that we check CALL_FROM_NEW_OR_DELETE_P, we don't need to consider whether an operator delete is replaceable, that consideration only applies to operator new. gcc/ChangeLog: * tree.h (DECL_IS_REPLACEABLE_OPERATOR_DELETE_P): Remove. * gimple.c (gimple_call_replaceable_operator_delete_p): Rename to gimple_call_operator_delete_p. * gimple.h: Adjust. * tree-ssa-dce.c: Adjust. * tree-ssa-structalias.c: Adjust. diff --git a/gcc/gimple.h b/gcc/gimple.h index 108ae846849..3c9b9965f5a 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -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); diff --git a/gcc/tree.h b/gcc/tree.h index f27a7399a37..c0a027a650d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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) diff --git a/gcc/gimple.c b/gcc/gimple.c index f07ddab7953..523d845de89 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -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; } diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index c9e0c8fd116..a0466127f9c 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -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 (stmt)) - && gimple_call_replaceable_operator_delete_p (as_a (stmt))); + && gimple_call_operator_delete_p (as_a (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 (stmt)) - && gimple_call_replaceable_operator_delete_p (as_a (stmt))))) + && gimple_call_operator_delete_p (as_a (stmt))))) { tree ptr = gimple_call_arg (stmt, 0); if (TREE_CODE (ptr) == SSA_NAME) diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 69de932b14c..30a8c93b4ff 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -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