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

Message ID ZyM7Wex+9+wEsbvB@tucnak
State New
Headers
Series c++: 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-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Jakub Jelinek Oct. 31, 2024, 8:10 a.m. UTC
  Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-10-31  Jakub Jelinek  <jakub@redhat.com>

	PR c++/117370
	* 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. 1, 2024, 4:28 p.m. UTC | #1
On 10/31/24 4:10 AM, Jakub Jelinek wrote:
> Hi!
> 
> 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.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2024-10-31  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/117370
> 	* 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/decl.cc.jj	2024-10-25 10:00:29.413768644 +0200
> +++ gcc/cp/decl.cc	2024-10-30 17:50:48.165446364 +0100
> @@ -16191,6 +16191,52 @@ 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_new_threshold
> +		  && args
> +		  && args != void_list_node)
> +		{
> +		  tree t = TREE_VALUE (args);
> +		  if (TREE_CODE (t) == ENUMERAL_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)), "align_val_t"))
> +		    args = TREE_CHAIN (args);
> +		}

Can this block be

if (aligned_allocation_fn_p (decl))
   args = TREE_CHAIN (args);

?

> +		      && 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.

Jason
  

Patch

--- gcc/cp/decl.cc.jj	2024-10-25 10:00:29.413768644 +0200
+++ gcc/cp/decl.cc	2024-10-30 17:50:48.165446364 +0100
@@ -16191,6 +16191,52 @@  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_new_threshold
+		  && args
+		  && args != void_list_node)
+		{
+		  tree t = TREE_VALUE (args);
+		  if (TREE_CODE (t) == ENUMERAL_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)), "align_val_t"))
+		    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
+		      && 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"))
+		    DECL_IS_REPLACEABLE_OPERATOR (decl) = 1;
+		}
+	    }
+	}
+
       if (op_flags & OVL_OP_FLAG_DELETE)
 	{
 	  DECL_SET_IS_OPERATOR_DELETE (decl, true);