c++, v2: Mark replaceable global operator new/delete with const std::nothrow_t& argument as DECL_IS_REPLACEABLE_OPERATOR [PR117370]

Message ID ZyUpT5r+tX38jzNS@tucnak
State New
Headers
Series c++, v2: Mark replaceable global operator new/delete with const std::nothrow_t& argument as DECL_IS_REPLACEABLE_OPERATOR [PR117370] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed

Commit Message

Jakub Jelinek Nov. 1, 2024, 7:17 p.m. UTC
  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  <jakub@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.



	Jakub
  

Comments

Jason Merrill Nov. 5, 2024, 12:26 a.m. UTC | #1
On 11/1/24 3:17 PM, Jakub Jelinek wrote:
> 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.

OK.

> 2024-11-01  Jakub Jelinek  <jakub@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
>
  

Patch

--- 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);