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

commit r15-1794-gbeb7a418aaef2ec8a812712110b007c091a73491
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Jul 2 22:08:45 2024 +0200

    c++: Implement C++26 P3144R2 - Deleting a Pointer to an Incomplete Type 
Should be Ill-formed [PR115747]
    
    The following patch implements the C++26 paper which makes delete
    and delete[] on incomplete class types invalid, previously it has
    been UB unless the class had trivial destructor and no custom
    deallocator.
    
    The patch uses permerror_opt, so -Wno-delete-incomplete makes it
    still compile without warnings like before, and -fpermissive makes
    it warn but not error; in SFINAE contexts it is considered an error
    in C++26 and later.
    
    2024-07-02  Jakub Jelinek  <ja...@redhat.com>
                Jason Merrill  <ja...@redhat.com>
    
            PR c++/115747
    gcc/cp/
            * init.cc: Implement C++26 P3144R2 - Deleting a Pointer to an
            Incomplete Type Should be Ill-formed.
            (build_vec_delete_1): Emit permerror_at and return error_mark_node
            for delete [] on incomplete type.
            (build_delete): Similarly for delete.
    gcc/testsuite/
            * g++.dg/init/delete1.C: Adjust expected diagnostics for C++26.
            * g++.dg/warn/Wdelete-incomplete-1.C: Likewise.
            * g++.dg/warn/incomplete1.C: Likewise.
            * g++.dg/ipa/pr85607.C: Likewise.
            * g++.dg/cpp26/delete1.C: New test.
            * g++.dg/cpp26/delete2.C: New test.
            * g++.dg/cpp26/delete3.C: New test.

Diff:
---
 gcc/cp/init.cc                                   | 38 ++++++++++++++++++++++--
 gcc/testsuite/g++.dg/cpp26/delete1.C             | 36 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp26/delete2.C             | 36 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp26/delete3.C             | 36 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/delete1.C              |  7 +++--
 gcc/testsuite/g++.dg/ipa/pr85607.C               |  7 +++--
 gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C |  7 +++--
 gcc/testsuite/g++.dg/warn/incomplete1.C          |  7 +++--
 8 files changed, 160 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 4a7ed7f5302..826a31c4a84 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4114,7 +4114,24 @@ build_vec_delete_1 (location_t loc, tree base, tree 
maxindex, tree type,
 
   if (!COMPLETE_TYPE_P (type))
     {
-      if (complain & tf_warning)
+      if (cxx_dialect > cxx23)
+       {
+         if (complain & tf_error)
+           {
+             int saved_errorcount = errorcount;
+             if (permerror_opt (loc, OPT_Wdelete_incomplete,
+                                "operator %<delete []%> used on "
+                                "incomplete type"))
+               {
+                 cxx_incomplete_type_inform (type);
+                 if (errorcount != saved_errorcount)
+                   return error_mark_node;
+               }
+           }
+         else
+           return error_mark_node;
+       }
+      else if (complain & tf_warning)
        {
          auto_diagnostic_group d;
          if (warning_at (loc, OPT_Wdelete_incomplete,
@@ -5178,7 +5195,24 @@ build_delete (location_t loc, tree otype, tree addr,
 
          if (!COMPLETE_TYPE_P (type))
            {
-             if (complain & tf_warning)
+             if (cxx_dialect > cxx23)
+               {
+                 if (complain & tf_error)
+                   {
+                     int saved_errorcount = errorcount;
+                     if (permerror_opt (loc, OPT_Wdelete_incomplete,
+                                        "operator %<delete%> used on "
+                                        "incomplete type"))
+                       {
+                         cxx_incomplete_type_inform (type);
+                         if (errorcount != saved_errorcount)
+                           return error_mark_node;
+                       }
+                   }
+                 else
+                   return error_mark_node;
+               }
+             else if (complain & tf_warning)
                {
                  auto_diagnostic_group d;
                  if (warning_at (loc, OPT_Wdelete_incomplete,
diff --git a/gcc/testsuite/g++.dg/cpp26/delete1.C 
b/gcc/testsuite/g++.dg/cpp26/delete1.C
new file mode 100644
index 00000000000..ca7766af1b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/delete1.C
@@ -0,0 +1,36 @@
+// C++26 P3144R2 - Deleting a Pointer to an Incomplete Type Should be 
Ill-formed
+// { dg-do compile { target c++26 } }
+
+struct S;      // { dg-message "forward declaration of 'struct S'" }
+struct T;      // { dg-message "forward declaration of 'struct T'" }
+struct U;      // { dg-message "forward declaration of 'struct U'" }
+
+void
+foo (S *p, T *q, U *r, S *s, T *t, U *u)
+{
+  delete p;    // { dg-error "operator 'delete' used on incomplete type" }
+  delete q;    // { dg-error "operator 'delete' used on incomplete type" }
+  delete r;    // { dg-error "operator 'delete' used on incomplete type" }
+  delete[] s;  // { dg-error "operator 'delete \\\[\\\]' used on incomplete 
type" }
+  delete[] t;  // { dg-error "operator 'delete \\\[\\\]' used on incomplete 
type" }
+  delete[] u;  // { dg-error "operator 'delete \\\[\\\]' used on incomplete 
type" }
+}
+
+struct S
+{
+  int s;
+};
+
+struct T
+{
+  int t;
+  ~T () {}
+};
+
+struct U
+{
+  int u;
+  void operator delete (void *) noexcept;
+  void operator delete[] (void *) noexcept;
+};
+
diff --git a/gcc/testsuite/g++.dg/cpp26/delete2.C 
b/gcc/testsuite/g++.dg/cpp26/delete2.C
new file mode 100644
index 00000000000..c5a6acf0c44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/delete2.C
@@ -0,0 +1,36 @@
+// C++26 P3144R2 - Deleting a Pointer to an Incomplete Type Should be 
Ill-formed
+// { dg-do compile { target c++26 } }
+// { dg-options "-Wno-delete-incomplete" }
+
+struct S;
+struct T;
+struct U;
+
+void
+foo (S *p, T *q, U *r, S *s, T *t, U *u)
+{
+  delete p;    // { dg-bogus "operator 'delete' used on incomplete type" }
+  delete q;    // { dg-bogus "operator 'delete' used on incomplete type" }
+  delete r;    // { dg-bogus "operator 'delete' used on incomplete type" }
+  delete[] s;  // { dg-bogus "operator 'delete \\\[\\\]' used on incomplete 
type" }
+  delete[] t;  // { dg-bogus "operator 'delete \\\[\\\]' used on incomplete 
type" }
+  delete[] u;  // { dg-bogus "operator 'delete \\\[\\\]' used on incomplete 
type" }
+}
+
+struct S
+{
+  int s;
+};
+
+struct T
+{
+  int t;
+  ~T () {}
+};
+
+struct U
+{
+  int u;
+  void operator delete (void *) noexcept;
+  void operator delete[] (void *) noexcept;
+};
diff --git a/gcc/testsuite/g++.dg/cpp26/delete3.C 
b/gcc/testsuite/g++.dg/cpp26/delete3.C
new file mode 100644
index 00000000000..d6702b7d678
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/delete3.C
@@ -0,0 +1,36 @@
+// C++26 P3144R2 - Deleting a Pointer to an Incomplete Type Should be 
Ill-formed
+// { dg-do compile { target c++26 } }
+// { dg-options "-fpermissive" }
+
+struct S;      // { dg-message "forward declaration of 'struct S'" }
+struct T;      // { dg-message "forward declaration of 'struct T'" }
+struct U;      // { dg-message "forward declaration of 'struct U'" }
+
+void
+foo (S *p, T *q, U *r, S *s, T *t, U *u)
+{
+  delete p;    // { dg-warning "operator 'delete' used on incomplete type" }
+  delete q;    // { dg-warning "operator 'delete' used on incomplete type" }
+  delete r;    // { dg-warning "operator 'delete' used on incomplete type" }
+  delete[] s;  // { dg-warning "operator 'delete \\\[\\\]' used on incomplete 
type" }
+  delete[] t;  // { dg-warning "operator 'delete \\\[\\\]' used on incomplete 
type" }
+  delete[] u;  // { dg-warning "operator 'delete \\\[\\\]' used on incomplete 
type" }
+}
+
+struct S
+{
+  int s;
+};
+
+struct T
+{
+  int t;
+  ~T () {}
+};
+
+struct U
+{
+  int u;
+  void operator delete (void *) noexcept;
+  void operator delete[] (void *) noexcept;
+};
diff --git a/gcc/testsuite/g++.dg/init/delete1.C 
b/gcc/testsuite/g++.dg/init/delete1.C
index 617c7ba8a10..f7c6257cfe4 100644
--- a/gcc/testsuite/g++.dg/init/delete1.C
+++ b/gcc/testsuite/g++.dg/init/delete1.C
@@ -3,7 +3,8 @@
 class C; // { dg-message "7:forward" }
 
 void foo(void *p) {
-  delete [] ((C*)p) ; // { dg-warning "3:possible problem detected in 
invocation of operator .delete \\\[\\\]." }
-  // { dg-message "3:neither the destructor nor the class-specific" "note" { 
target *-*-* } .-1 }
-  // { dg-warning "invalid use of incomplete type" "" { target *-*-* } .-2 }
+  delete [] ((C*)p) ; // { dg-warning "3:possible problem detected in 
invocation of operator .delete \\\[\\\]." "" { target c++23_down } }
+  // { dg-message "3:neither the destructor nor the class-specific" "note" { 
target c++23_down } .-1 }
+  // { dg-warning "invalid use of incomplete type" "" { target c++23_down } 
.-2 }
+  // { dg-error "operator 'delete \\\[\\\]' used on incomplete type" "" { 
target c++26 } .-3 }
 }
diff --git a/gcc/testsuite/g++.dg/ipa/pr85607.C 
b/gcc/testsuite/g++.dg/ipa/pr85607.C
index 9f619096152..51000c05c30 100644
--- a/gcc/testsuite/g++.dg/ipa/pr85607.C
+++ b/gcc/testsuite/g++.dg/ipa/pr85607.C
@@ -3,12 +3,13 @@
 
 class A;       // { dg-message "7:forward declaration of 'class A'" }
 
-A *a;          // { dg-warning "4:'a' has incomplete type" }
+A *a;          // { dg-warning "4:'a' has incomplete type" "" { target 
c++23_down } }
 
 int
 main (int argc, char **argv)
 {
-  delete a;    // { dg-warning "3:possible problem detected in invocation of 
.operator delete." "warn" }
-  // { dg-message "3:neither the destructor nor the class-specific" "note" { 
target *-*-* } .-1 }
+  delete a;    // { dg-warning "3:possible problem detected in invocation of 
.operator delete." "warn" { target c++23_down } }
+  // { dg-message "3:neither the destructor nor the class-specific" "note" { 
target c++23_down } .-1 }
+  // { dg-error "operator 'delete' used on incomplete type" "" { target c++26 
} .-2 }
   return 0;
 }
diff --git a/gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C 
b/gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C
index d0c40e23db9..8be3446c06a 100644
--- a/gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C
+++ b/gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C
@@ -2,7 +2,8 @@
 
 class Foo;         // { dg-message "7:forward declaration" }
 int main() {
-   Foo* p;         // { dg-warning "9:.p. has incomplete type" }
-   delete [] p;    // { dg-warning "4:possible problem detected in invocation 
of operator .delete \\\[\\\]." }
-   // { dg-message "4:neither the destructor nor the class-specific" "note" { 
target *-*-* } .-1 }
+   Foo* p;         // { dg-warning "9:.p. has incomplete type" "" { target 
c++23_down } }
+   delete [] p;    // { dg-warning "4:possible problem detected in invocation 
of operator .delete \\\[\\\]." "" { target c++23_down } }
+   // { dg-message "4:neither the destructor nor the class-specific" "note" { 
target c++23_down } .-1 }
+   // { dg-error "operator 'delete \\\[\\\]' used on incomplete type" "" { 
target c++26 } .-2 }
 }
diff --git a/gcc/testsuite/g++.dg/warn/incomplete1.C 
b/gcc/testsuite/g++.dg/warn/incomplete1.C
index aa44c7ba3fb..f9e2edd224b 100644
--- a/gcc/testsuite/g++.dg/warn/incomplete1.C
+++ b/gcc/testsuite/g++.dg/warn/incomplete1.C
@@ -11,12 +11,13 @@
 
 class A;       // { dg-message "7:forward declaration of 'class A'" }
 
-A *a;          // { dg-warning "4:'a' has incomplete type" }
+A *a;          // { dg-warning "4:'a' has incomplete type" "" { target 
c++23_down } }
 
 int
 main (int argc, char **argv)
 {
-  delete a;    // { dg-warning "3:possible problem detected in invocation of 
.operator delete." "warn" }
-  // { dg-message "3:neither the destructor nor the class-specific" "note" { 
target *-*-* } .-1 }
+  delete a;    // { dg-warning "3:possible problem detected in invocation of 
.operator delete." "warn" { target c++23_down } }
+  // { dg-message "3:neither the destructor nor the class-specific" "note" { 
target c++23_down } .-1 }
+  // { dg-error "operator 'delete' used on incomplete type" "" { target c++26 
} .-2 }
   return 0;
 }

Reply via email to