https://gcc.gnu.org/g:eef599adc2415ebf28c4295203dfd26f92ef9420

commit r16-6266-geef599adc2415ebf28c4295203dfd26f92ef9420
Author: Jakub Jelinek <[email protected]>
Date:   Fri Dec 19 10:13:45 2025 +0100

    c++: Reject array new with -fexceptions with deleted dtor [PR123030]
    
    For array new and -fexceptions, we only try to build cleanup if
    TYPE_HAS_NONTRIVIAL_DESTRUCTOR and so don't complain if the
    array element has trivial but deleted destructor.
    
    The following patch changes it to build the dtor whenever
    type_build_dtor_call but only registers it as cleanup if the cleanup
    has TREE_SIDE_EFFECTS.  build_vec_delete_1 has a special
    case for these type_build_dtor_call && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR
    cases where it does less work.
    
    Though, I wonder if we also shouldn't test whether the ctor isn't noexcept,
    then we wouldn't have to change the new4.C test.  Though, clang++ rejects
    that as well even when it has noexcept ctor.
    
    2025-12-19  Jakub Jelinek  <[email protected]>
    
            PR c++/123030
            * init.cc (build_vec_init): Call build_vec_delete_1 for -fexceptions
            even if just type_build_dtor_call, not only when
            TYPE_HAS_NONTRIVIAL_DESTRUCTOR.  But register cleanups only
            for TYPE_HAS_NONTRIVIAL_DESTRUCTOR.
    
            * g++.dg/cpp0x/deleted18.C: New test.
            * g++.dg/cpp0x/new4.C: Expect an error.

Diff:
---
 gcc/cp/init.cc                         | 45 +++++++++++++++++++---------------
 gcc/testsuite/g++.dg/cpp0x/deleted18.C | 20 +++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/new4.C      |  2 +-
 3 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 1b7f3e6b41c9..4391022f52dd 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4785,11 +4785,12 @@ build_vec_init (tree base, tree maxindex, tree init,
   /* Protect the entire array initialization so that we can destroy
      the partially constructed array if an exception is thrown.
      But don't do this if we're assigning.  */
-  if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+  if (flag_exceptions
       /* And don't clean up from clobbers, the actual initialization will
         follow as a separate build_vec_init.  */
       && !(init && TREE_CLOBBER_P (init))
-      && from_array != 2)
+      && from_array != 2
+      && type_build_dtor_call (type))
     {
       tree e;
       tree m = cp_build_binary_op (input_location,
@@ -4812,24 +4813,28 @@ build_vec_init (tree base, tree maxindex, tree init,
                              /*in_cleanup*/true);
       if (e == error_mark_node)
        errors = true;
-      TARGET_EXPR_CLEANUP (iterator_targ) = e;
-      CLEANUP_EH_ONLY (iterator_targ) = true;
-
-      /* Since we push this cleanup before doing any initialization, cleanups
-        for any temporaries in the initialization are naturally within our
-        cleanup region, so we don't want wrap_temporary_cleanups to do
-        anything for arrays.  But if the array is a subobject, we need to
-        tell split_nonconstant_init or cp_genericize_target_expr how to turn
-        off this cleanup in favor of the cleanup for the complete object.
-
-        ??? For an array temporary such as an initializer_list backing array,
-        it would avoid redundancy to leave this cleanup active, clear
-        CLEANUP_EH_ONLY, and not build another cleanup for the temporary
-        itself.  But that breaks when gimplify_target_expr adds a clobber
-        cleanup that runs before the build_vec_init cleanup.  */
-      if (cleanup_flags)
-       vec_safe_push (*cleanup_flags,
-                      build_tree_list (rval, build_zero_cst (ptype)));
+      else if (TREE_SIDE_EFFECTS (e))
+       {
+         TARGET_EXPR_CLEANUP (iterator_targ) = e;
+         CLEANUP_EH_ONLY (iterator_targ) = true;
+
+         /* Since we push this cleanup before doing any initialization,
+            cleanups for any temporaries in the initialization are naturally
+            within our cleanup region, so we don't want
+            wrap_temporary_cleanups to do anything for arrays.  But if the
+            array is a subobject, we need to tell split_nonconstant_init or
+            cp_genericize_target_expr how to turn off this cleanup in favor
+            of the cleanup for the complete object.
+
+            ??? For an array temporary such as an initializer_list backing
+            array, it would avoid redundancy to leave this cleanup active,
+            clear CLEANUP_EH_ONLY, and not build another cleanup for the
+            temporary itself.  But that breaks when gimplify_target_expr adds
+            a clobber cleanup that runs before the build_vec_init cleanup.  */
+         if (cleanup_flags)
+           vec_safe_push (*cleanup_flags,
+                          build_tree_list (rval, build_zero_cst (ptype)));
+       }
     }
 
   /* Should we try to create a constant initializer?  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/deleted18.C 
b/gcc/testsuite/g++.dg/cpp0x/deleted18.C
new file mode 100644
index 000000000000..f8815ad3d9b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/deleted18.C
@@ -0,0 +1,20 @@
+// PR c++/123030
+// { dg-do compile { target c++11 } }
+
+int n;
+struct Y {
+  Y () { if (++n == 2) throw 42; }
+  ~Y () = delete;      // { dg-message "declared here" }
+};
+
+int
+main ()
+{
+  try
+    {
+      new Y[2];                // { dg-error "use of deleted function 
'Y::~Y\\\(\\\)'" }
+    }
+  catch (...)
+    {
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/new4.C 
b/gcc/testsuite/g++.dg/cpp0x/new4.C
index 728ef4ee7ce3..03ba55e040d0 100644
--- a/gcc/testsuite/g++.dg/cpp0x/new4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/new4.C
@@ -3,7 +3,7 @@
 
 struct A { ~A () = delete; };
 A *pa{new A{}};
-A *pa2{new A[2]{}};
+A *pa2{new A[2]{}};            // { dg-error "use of deleted function 
'A::~A\\\(\\\)'" }
 
 class B { ~B () = default; };
 B *pb{new B{}};

Reply via email to