On Fri, Nov 01, 2024 at 12:28:52PM -0400, Jason Merrill wrote: > Can this block be > > if (aligned_allocation_fn_p (decl)) > args = TREE_CHAIN (args); > > ?
Yes. > > + && TREE_CODE (t) == RECORD_TYPE > > + && DECL_NAMESPACE_STD_P (CP_TYPE_CONTEXT (t)) > > + && TYPE_NAME (t) > > + && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL > > + && DECL_NAME (TYPE_NAME (t)) > > + && id_equal (DECL_NAME (TYPE_NAME (t)), "nothrow_t")) > > Let's factor is_std_allocator into a function taking a const char * and use > that here as well. So like this? I've verified on #include <new> with -std=c++23 it marks exactly 8 operators which is the expected count. 2024-11-01 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. --- gcc/cp/cp-tree.h.jj 2024-11-01 19:32:12.961053085 +0100 +++ gcc/cp/cp-tree.h 2024-11-01 20:10:18.246350835 +0100 @@ -8706,6 +8706,7 @@ extern bool is_rvalue_constant_expressio 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); --- gcc/cp/constexpr.cc.jj 2024-10-25 10:00:29.407768730 +0200 +++ gcc/cp/constexpr.cc 2024-11-01 20:12:04.835825528 +0100 @@ -2363,22 +2363,30 @@ is_std_construct_at (const constexpr_cal && 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 --- gcc/cp/decl.cc.jj 2024-10-31 21:17:07.059018373 +0100 +++ gcc/cp/decl.cc 2024-11-01 20:12:48.506200598 +0100 @@ -16191,6 +16191,36 @@ grok_op_properties (tree decl, bool comp } } + /* 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); Jakub