c++: Diagnose constexpr delete [] new int; and delete new int[N]; [PR95808]
authorJakub Jelinek <jakub@redhat.com>
Thu, 29 Oct 2020 15:27:01 +0000 (16:27 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 29 Oct 2020 15:27:01 +0000 (16:27 +0100)
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.

2020-10-29  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/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C [new file with mode: 0644]

index 7ebdd308dcd67e3b2099f03f824cde031b6c9a53..37c836a8a7b08ea017a5693244a9378b2cd2ff17 100644 (file)
@@ -2288,7 +2288,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
            {
              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 constexpr_ctx *ctx, tree t,
                  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++;
@@ -4605,7 +4645,9 @@ non_const_var_error (location_t loc, tree r)
   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");
@@ -6365,8 +6407,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
            && 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));
@@ -6380,7 +6424,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                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 (var) == heap_uninit_identifier
+                ? heap_identifier : heap_vec_identifier);
            TREE_TYPE (var)
              = build_new_constexpr_heap_type (elt_type, cookie_size,
                                               var_size);
@@ -6651,6 +6697,8 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/)
   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;
 
index 4f9038eb201cc7e6e6fdf83d2404450d6acc5352..20774f826200048ff0df323740771a2ed6396d35 100644 (file)
@@ -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_MAX];
 #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]
 
index ee3c353935d006248a0f9fb99b2a37fa947defe6..39f56b81275af30f30d6023b6b37742a2fcbecac 100644 (file)
@@ -4245,6 +4245,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}
   };
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new15.C
new file mode 100644 (file)
index 0000000..e97e7aa
--- /dev/null
@@ -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 ();