https://gcc.gnu.org/g:c1bbad07c8686c858ea58ffdb9db8f964bf485c6
commit r15-4953-gc1bbad07c8686c858ea58ffdb9db8f964bf485c6 Author: Jakub Jelinek <ja...@redhat.com> Date: Tue Nov 5 08:58:28 2024 +0100 c++: Mark replaceable global operator new/delete with const std::nothrow_t& argument as DECL_IS_REPLACEABLE_OPERATOR [PR117370] cxx_init_decl_processing predeclares 12 out of the 20 replaceable global new/delete operators and sets DECL_IS_REPLACEABLE_OPERATOR on those. But it doesn't handle the remaining 8, in particular void* operator new(std::size_t, const std::nothrow_t&) noexcept; void* operator new[](std::size_t, const std::nothrow_t&) noexcept; void operator delete(void*, const std::nothrow_t&) noexcept; void operator delete[](void*, const std::nothrow_t&) noexcept; void* operator new(std::size_t, std::align_val_t, const std::nothrow_t&) noexcept; void* operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) noexcept; void operator delete(void*, std::align_val_t, const std::nothrow_t&) noexcept; void operator delete[](void*, std::align_val_t, const std::nothrow_t&) noexcept; The following patch sets that flag during grok_op_properties for those, so that they don't need to be predeclared. The patch doesn't fix the whole PR, as some work is needed on the CDDCE side too, unlike the throwing operator new case the if (ptr) conditional around operator delete isn't removed by VRP and so we need to handle conditional delete for unconditional new. 2024-11-05 Jakub Jelinek <ja...@redhat.com> PR c++/117370 * cp-tree.h (is_std_class): Declare. * constexpr.cc (is_std_class): New function. (is_std_allocator): Use it. * decl.cc (grok_op_properties): Mark global replaceable operator new/delete operators with const std::nothrow_t & last argument with DECL_IS_REPLACEABLE_OPERATOR. Diff: --- gcc/cp/constexpr.cc | 16 ++++++++++++---- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.cc | 30 ++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index c141c0a2844b..71e6dc4ef326 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -2363,22 +2363,30 @@ is_std_construct_at (const constexpr_call *call) && is_std_construct_at (call->fundef->decl)); } -/* True if CTX is an instance of std::allocator. */ +/* True if CTX is an instance of std::NAME class. */ bool -is_std_allocator (tree ctx) +is_std_class (tree ctx, const char *name) { if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx)) return false; tree decl = TYPE_MAIN_DECL (ctx); - tree name = DECL_NAME (decl); - if (name == NULL_TREE || !id_equal (name, "allocator")) + tree dname = DECL_NAME (decl); + if (dname == NULL_TREE || !id_equal (dname, name)) return false; return decl_in_std_namespace_p (decl); } +/* True if CTX is an instance of std::allocator. */ + +bool +is_std_allocator (tree ctx) +{ + return is_std_class (ctx, "allocator"); +} + /* Return true if FNDECL is std::allocator<T>::{,de}allocate. */ static inline bool diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f98a1de42cae..92d1dba6a5c9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8706,6 +8706,7 @@ extern bool is_rvalue_constant_expression (tree); extern bool is_nondependent_constant_expression (tree); extern bool is_nondependent_static_init_expression (tree); extern bool is_static_init_expression (tree); +extern bool is_std_class (tree, const char *); extern bool is_std_allocator (tree); extern bool potential_rvalue_constant_expression (tree); extern bool require_potential_constant_expression (tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 0e4533c6faba..b4e7ceefedb0 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -16191,6 +16191,36 @@ grok_op_properties (tree decl, bool complain) } } + /* Check for replaceable global new/delete operators with + const std::nothrow_t & last argument, other replaceable global + new/delete operators are marked in cxx_init_decl_processing. */ + if (CP_DECL_CONTEXT (decl) == global_namespace) + { + tree args = argtypes; + if (args + && args != void_list_node + && same_type_p (TREE_VALUE (args), + (op_flags & OVL_OP_FLAG_DELETE) + ? ptr_type_node : size_type_node)) + { + args = TREE_CHAIN (args); + if (aligned_allocation_fn_p (decl)) + args = TREE_CHAIN (args); + if (args + && args != void_list_node + && TREE_CHAIN (args) == void_list_node) + { + tree t = TREE_VALUE (args); + if (TYPE_REF_P (t) + && !TYPE_REF_IS_RVALUE (t) + && (t = TREE_TYPE (t)) + && TYPE_QUALS (t) == TYPE_QUAL_CONST + && is_std_class (t, "nothrow_t")) + DECL_IS_REPLACEABLE_OPERATOR (decl) = 1; + } + } + } + if (op_flags & OVL_OP_FLAG_DELETE) { DECL_SET_IS_OPERATOR_DELETE (decl, true);