diff mbox series

c++: Diagnose constexpr delete [] new int; and delete new int[N]; [PR95808]

Message ID 20201016094254.GE2176@tucnak
State New
Headers show
Series c++: Diagnose constexpr delete [] new int; and delete new int[N]; [PR95808] | expand

Commit Message

Jakub Jelinek Oct. 16, 2020, 9:42 a.m. UTC
Hi!

This patch diagnoses delete [] new int; and delete new int[1]; in constexpr
contexts by remembering
IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun)) & OVL_OP_FLAG_VEC
from the operator new and checking it at operator delete time.

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

2020-10-16  Jakub Jelinek  <jakub@redhat.com>

	PR c++/95808
	* cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_VEC_UNINIT_IDENTIFIER
	and CPTI_HEAP_VEC_IDENTIFIER.
	(heap_vec_uninit_identifier, heap_vec_identifier): Define.
	* decl.c (initialize_predefined_identifiers): Initialize those
	identifiers.
	* constexpr.c (cxx_eval_call_expression): Reject array allocations
	deallocated with non-array deallocation or non-array allocations
	deallocated with array deallocation.
	(non_const_var_error): Handle heap_vec_uninit_identifier and
	heap_vec_identifier too.
	(cxx_eval_constant_expression): Handle also heap_vec_uninit_identifier
	and in that case during initialization replace it with
	heap_vec_identifier.
	(find_heap_var_refs): Handle heap_vec_uninit_identifier and
	heap_vec_identifier too.

	* g++.dg/cpp2a/constexpr-new15.C: New test.


	Jakub

Comments

Jason Merrill Oct. 29, 2020, 3:14 p.m. UTC | #1
On 10/16/20 5:42 AM, Jakub Jelinek wrote:
> Hi!
> 
> This patch diagnoses delete [] new int; and delete new int[1]; in constexpr
> contexts by remembering
> IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun)) & OVL_OP_FLAG_VEC
> from the operator new and checking it at operator delete time.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2020-10-16  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/95808
> 	* cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_VEC_UNINIT_IDENTIFIER
> 	and CPTI_HEAP_VEC_IDENTIFIER.
> 	(heap_vec_uninit_identifier, heap_vec_identifier): Define.
> 	* decl.c (initialize_predefined_identifiers): Initialize those
> 	identifiers.
> 	* constexpr.c (cxx_eval_call_expression): Reject array allocations
> 	deallocated with non-array deallocation or non-array allocations
> 	deallocated with array deallocation.
> 	(non_const_var_error): Handle heap_vec_uninit_identifier and
> 	heap_vec_identifier too.
> 	(cxx_eval_constant_expression): Handle also heap_vec_uninit_identifier
> 	and in that case during initialization replace it with
> 	heap_vec_identifier.
> 	(find_heap_var_refs): Handle heap_vec_uninit_identifier and
> 	heap_vec_identifier too.
> 
> 	* g++.dg/cpp2a/constexpr-new15.C: New test.
> 
> --- gcc/cp/cp-tree.h.jj	2020-10-14 22:05:19.274858485 +0200
> +++ gcc/cp/cp-tree.h	2020-10-15 16:29:12.136899207 +0200
> @@ -178,6 +178,8 @@ enum cp_tree_index
>       CPTI_HEAP_UNINIT_IDENTIFIER,
>       CPTI_HEAP_IDENTIFIER,
>       CPTI_HEAP_DELETED_IDENTIFIER,
> +    CPTI_HEAP_VEC_UNINIT_IDENTIFIER,
> +    CPTI_HEAP_VEC_IDENTIFIER,
>   
>       CPTI_LANG_NAME_C,
>       CPTI_LANG_NAME_CPLUSPLUS,
> @@ -322,6 +324,8 @@ extern GTY(()) tree cp_global_trees[CPTI
>   #define heap_uninit_identifier		cp_global_trees[CPTI_HEAP_UNINIT_IDENTIFIER]
>   #define heap_identifier			cp_global_trees[CPTI_HEAP_IDENTIFIER]
>   #define heap_deleted_identifier		cp_global_trees[CPTI_HEAP_DELETED_IDENTIFIER]
> +#define heap_vec_uninit_identifier	cp_global_trees[CPTI_HEAP_VEC_UNINIT_IDENTIFIER]
> +#define heap_vec_identifier		cp_global_trees[CPTI_HEAP_VEC_IDENTIFIER]
>   #define lang_name_c			cp_global_trees[CPTI_LANG_NAME_C]
>   #define lang_name_cplusplus		cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
>   
> --- gcc/cp/decl.c.jj	2020-10-14 22:05:19.293858210 +0200
> +++ gcc/cp/decl.c	2020-10-15 16:30:05.690125490 +0200
> @@ -4242,6 +4242,8 @@ initialize_predefined_identifiers (void)
>       {"heap uninit", &heap_uninit_identifier, cik_normal},
>       {"heap ", &heap_identifier, cik_normal},
>       {"heap deleted", &heap_deleted_identifier, cik_normal},
> +    {"heap [] uninit", &heap_vec_uninit_identifier, cik_normal},
> +    {"heap []", &heap_vec_identifier, cik_normal},
>       {NULL, NULL, cik_normal}
>     };
>   
> --- gcc/cp/constexpr.c.jj	2020-10-01 11:16:36.390959542 +0200
> +++ gcc/cp/constexpr.c	2020-10-15 17:02:31.036021476 +0200
> @@ -2288,7 +2288,11 @@ cxx_eval_call_expression (const constexp
>   	    {
>   	      tree type = build_array_type_nelts (char_type_node,
>   						  tree_to_uhwi (arg0));
> -	      tree var = build_decl (loc, VAR_DECL, heap_uninit_identifier,
> +	      tree var = build_decl (loc, VAR_DECL,
> +				     (IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun))
> +				      & OVL_OP_FLAG_VEC)
> +				     ? heap_vec_uninit_identifier
> +				     : heap_uninit_identifier,
>   				     type);
>   	      DECL_ARTIFICIAL (var) = 1;
>   	      TREE_STATIC (var) = 1;
> @@ -2306,6 +2310,42 @@ cxx_eval_call_expression (const constexp
>   		  if (DECL_NAME (var) == heap_uninit_identifier
>   		      || DECL_NAME (var) == heap_identifier)
>   		    {
> +		      if (IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun))
> +			  & OVL_OP_FLAG_VEC)
> +			{
> +			  if (!ctx->quiet)
> +			    {
> +			      error_at (loc, "array deallocation of object "
> +					     "allocated with non-array "
> +					     "allocation");
> +			      inform (DECL_SOURCE_LOCATION (var),
> +				      "allocation performed here");
> +			    }
> +			  *non_constant_p = true;
> +			  return t;
> +			}
> +		      DECL_NAME (var) = heap_deleted_identifier;
> +		      ctx->global->values.remove (var);
> +		      ctx->global->heap_dealloc_count++;
> +		      return void_node;
> +		    }
> +		  else if (DECL_NAME (var) == heap_vec_uninit_identifier
> +			   || DECL_NAME (var) == heap_vec_identifier)
> +		    {
> +		      if ((IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun))
> +			   & OVL_OP_FLAG_VEC) == 0)
> +			{
> +			  if (!ctx->quiet)
> +			    {
> +			      error_at (loc, "non-array deallocation of "
> +					     "object allocated with array "
> +					     "allocation");
> +			      inform (DECL_SOURCE_LOCATION (var),
> +				      "allocation performed here");
> +			    }
> +			  *non_constant_p = true;
> +			  return t;
> +			}
>   		      DECL_NAME (var) = heap_deleted_identifier;
>   		      ctx->global->values.remove (var);
>   		      ctx->global->heap_dealloc_count++;
> @@ -4591,7 +4631,9 @@ non_const_var_error (location_t loc, tre
>     auto_diagnostic_group d;
>     tree type = TREE_TYPE (r);
>     if (DECL_NAME (r) == heap_uninit_identifier
> -      || DECL_NAME (r) == heap_identifier)
> +      || DECL_NAME (r) == heap_identifier
> +      || DECL_NAME (r) == heap_vec_uninit_identifier
> +      || DECL_NAME (r) == heap_vec_identifier)
>       {
>         error_at (loc, "the content of uninitialized storage is not usable "
>   		"in a constant expression");
> @@ -6351,8 +6393,10 @@ cxx_eval_constant_expression (const cons
>   	    && TREE_TYPE (op) == ptr_type_node
>   	    && TREE_CODE (TREE_OPERAND (op, 0)) == ADDR_EXPR
>   	    && VAR_P (TREE_OPERAND (TREE_OPERAND (op, 0), 0))
> -	    && DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
> -					0)) == heap_uninit_identifier)
> +	    && (DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
> +					 0)) == heap_uninit_identifier
> +		|| DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
> +					    0)) == heap_vec_uninit_identifier))
>   	  {
>   	    tree var = TREE_OPERAND (TREE_OPERAND (op, 0), 0);
>   	    tree var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
> @@ -6366,7 +6410,10 @@ cxx_eval_constant_expression (const cons
>   		elt_type = TREE_TYPE (TREE_TYPE (fld2));
>   		cookie_size = TYPE_SIZE_UNIT (TREE_TYPE (fld1));
>   	      }
> -	    DECL_NAME (var) = heap_identifier;
> +	    DECL_NAME (var)
> +	      = (DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
> +					  0)) == heap_uninit_identifier

This can be

   = (DECL_NAME (var) == heap_uninit_identifier

OK with that change.

> +		 ? heap_identifier : heap_vec_identifier);
>   	    TREE_TYPE (var)
>   	      = build_new_constexpr_heap_type (elt_type, cookie_size,
>   					       var_size);
> @@ -6637,6 +6684,8 @@ find_heap_var_refs (tree *tp, int *walk_
>     if (VAR_P (*tp)
>         && (DECL_NAME (*tp) == heap_uninit_identifier
>   	  || DECL_NAME (*tp) == heap_identifier
> +	  || DECL_NAME (*tp) == heap_vec_uninit_identifier
> +	  || DECL_NAME (*tp) == heap_vec_identifier
>   	  || DECL_NAME (*tp) == heap_deleted_identifier))
>       return *tp;
>   
> --- gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C.jj	2020-10-15 17:08:22.347946251 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C	2020-10-15 17:07:49.009427880 +0200
> @@ -0,0 +1,21 @@
> +// PR c++/95808
> +// { dg-do compile { target c++20 } }
> +
> +constexpr
> +bool foo ()
> +{
> +  int *p = new int;	// { dg-message "allocation performed here" }
> +  delete[] p;		// { dg-error "array deallocation of object allocated with non-array allocation" }
> +  return false;
> +}
> +
> +constexpr
> +bool bar ()
> +{
> +  int *p = new int[1];	// { dg-message "allocation performed here" }
> +  delete p;		// { dg-error "non-array deallocation of object allocated with array allocation" }
> +  return false;
> +}
> +
> +constexpr auto x = foo ();
> +constexpr auto y = bar ();
> 
> 	Jakub
>
diff mbox series

Patch

--- gcc/cp/cp-tree.h.jj	2020-10-14 22:05:19.274858485 +0200
+++ gcc/cp/cp-tree.h	2020-10-15 16:29:12.136899207 +0200
@@ -178,6 +178,8 @@  enum cp_tree_index
     CPTI_HEAP_UNINIT_IDENTIFIER,
     CPTI_HEAP_IDENTIFIER,
     CPTI_HEAP_DELETED_IDENTIFIER,
+    CPTI_HEAP_VEC_UNINIT_IDENTIFIER,
+    CPTI_HEAP_VEC_IDENTIFIER,
 
     CPTI_LANG_NAME_C,
     CPTI_LANG_NAME_CPLUSPLUS,
@@ -322,6 +324,8 @@  extern GTY(()) tree cp_global_trees[CPTI
 #define heap_uninit_identifier		cp_global_trees[CPTI_HEAP_UNINIT_IDENTIFIER]
 #define heap_identifier			cp_global_trees[CPTI_HEAP_IDENTIFIER]
 #define heap_deleted_identifier		cp_global_trees[CPTI_HEAP_DELETED_IDENTIFIER]
+#define heap_vec_uninit_identifier	cp_global_trees[CPTI_HEAP_VEC_UNINIT_IDENTIFIER]
+#define heap_vec_identifier		cp_global_trees[CPTI_HEAP_VEC_IDENTIFIER]
 #define lang_name_c			cp_global_trees[CPTI_LANG_NAME_C]
 #define lang_name_cplusplus		cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
 
--- gcc/cp/decl.c.jj	2020-10-14 22:05:19.293858210 +0200
+++ gcc/cp/decl.c	2020-10-15 16:30:05.690125490 +0200
@@ -4242,6 +4242,8 @@  initialize_predefined_identifiers (void)
     {"heap uninit", &heap_uninit_identifier, cik_normal},
     {"heap ", &heap_identifier, cik_normal},
     {"heap deleted", &heap_deleted_identifier, cik_normal},
+    {"heap [] uninit", &heap_vec_uninit_identifier, cik_normal},
+    {"heap []", &heap_vec_identifier, cik_normal},
     {NULL, NULL, cik_normal}
   };
 
--- gcc/cp/constexpr.c.jj	2020-10-01 11:16:36.390959542 +0200
+++ gcc/cp/constexpr.c	2020-10-15 17:02:31.036021476 +0200
@@ -2288,7 +2288,11 @@  cxx_eval_call_expression (const constexp
 	    {
 	      tree type = build_array_type_nelts (char_type_node,
 						  tree_to_uhwi (arg0));
-	      tree var = build_decl (loc, VAR_DECL, heap_uninit_identifier,
+	      tree var = build_decl (loc, VAR_DECL,
+				     (IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun))
+				      & OVL_OP_FLAG_VEC)
+				     ? heap_vec_uninit_identifier
+				     : heap_uninit_identifier,
 				     type);
 	      DECL_ARTIFICIAL (var) = 1;
 	      TREE_STATIC (var) = 1;
@@ -2306,6 +2310,42 @@  cxx_eval_call_expression (const constexp
 		  if (DECL_NAME (var) == heap_uninit_identifier
 		      || DECL_NAME (var) == heap_identifier)
 		    {
+		      if (IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun))
+			  & OVL_OP_FLAG_VEC)
+			{
+			  if (!ctx->quiet)
+			    {
+			      error_at (loc, "array deallocation of object "
+					     "allocated with non-array "
+					     "allocation");
+			      inform (DECL_SOURCE_LOCATION (var),
+				      "allocation performed here");
+			    }
+			  *non_constant_p = true;
+			  return t;
+			}
+		      DECL_NAME (var) = heap_deleted_identifier;
+		      ctx->global->values.remove (var);
+		      ctx->global->heap_dealloc_count++;
+		      return void_node;
+		    }
+		  else if (DECL_NAME (var) == heap_vec_uninit_identifier
+			   || DECL_NAME (var) == heap_vec_identifier)
+		    {
+		      if ((IDENTIFIER_OVL_OP_FLAGS (DECL_NAME (fun))
+			   & OVL_OP_FLAG_VEC) == 0)
+			{
+			  if (!ctx->quiet)
+			    {
+			      error_at (loc, "non-array deallocation of "
+					     "object allocated with array "
+					     "allocation");
+			      inform (DECL_SOURCE_LOCATION (var),
+				      "allocation performed here");
+			    }
+			  *non_constant_p = true;
+			  return t;
+			}
 		      DECL_NAME (var) = heap_deleted_identifier;
 		      ctx->global->values.remove (var);
 		      ctx->global->heap_dealloc_count++;
@@ -4591,7 +4631,9 @@  non_const_var_error (location_t loc, tre
   auto_diagnostic_group d;
   tree type = TREE_TYPE (r);
   if (DECL_NAME (r) == heap_uninit_identifier
-      || DECL_NAME (r) == heap_identifier)
+      || DECL_NAME (r) == heap_identifier
+      || DECL_NAME (r) == heap_vec_uninit_identifier
+      || DECL_NAME (r) == heap_vec_identifier)
     {
       error_at (loc, "the content of uninitialized storage is not usable "
 		"in a constant expression");
@@ -6351,8 +6393,10 @@  cxx_eval_constant_expression (const cons
 	    && TREE_TYPE (op) == ptr_type_node
 	    && TREE_CODE (TREE_OPERAND (op, 0)) == ADDR_EXPR
 	    && VAR_P (TREE_OPERAND (TREE_OPERAND (op, 0), 0))
-	    && DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
-					0)) == heap_uninit_identifier)
+	    && (DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
+					 0)) == heap_uninit_identifier
+		|| DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
+					    0)) == heap_vec_uninit_identifier))
 	  {
 	    tree var = TREE_OPERAND (TREE_OPERAND (op, 0), 0);
 	    tree var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
@@ -6366,7 +6410,10 @@  cxx_eval_constant_expression (const cons
 		elt_type = TREE_TYPE (TREE_TYPE (fld2));
 		cookie_size = TYPE_SIZE_UNIT (TREE_TYPE (fld1));
 	      }
-	    DECL_NAME (var) = heap_identifier;
+	    DECL_NAME (var)
+	      = (DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
+					  0)) == heap_uninit_identifier
+		 ? heap_identifier : heap_vec_identifier);
 	    TREE_TYPE (var)
 	      = build_new_constexpr_heap_type (elt_type, cookie_size,
 					       var_size);
@@ -6637,6 +6684,8 @@  find_heap_var_refs (tree *tp, int *walk_
   if (VAR_P (*tp)
       && (DECL_NAME (*tp) == heap_uninit_identifier
 	  || DECL_NAME (*tp) == heap_identifier
+	  || DECL_NAME (*tp) == heap_vec_uninit_identifier
+	  || DECL_NAME (*tp) == heap_vec_identifier
 	  || DECL_NAME (*tp) == heap_deleted_identifier))
     return *tp;
 
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C.jj	2020-10-15 17:08:22.347946251 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C	2020-10-15 17:07:49.009427880 +0200
@@ -0,0 +1,21 @@ 
+// PR c++/95808
+// { dg-do compile { target c++20 } }
+
+constexpr
+bool foo ()
+{
+  int *p = new int;	// { dg-message "allocation performed here" }
+  delete[] p;		// { dg-error "array deallocation of object allocated with non-array allocation" }
+  return false;
+}
+
+constexpr
+bool bar ()
+{
+  int *p = new int[1];	// { dg-message "allocation performed here" }
+  delete p;		// { dg-error "non-array deallocation of object allocated with array allocation" }
+  return false;
+}
+
+constexpr auto x = foo ();
+constexpr auto y = bar ();