]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Implement C++26 P3144R2 - Deleting a Pointer to an Incomplete Type Should be...
authorJakub Jelinek <jakub@redhat.com>
Tue, 2 Jul 2024 20:08:45 +0000 (22:08 +0200)
committerJakub Jelinek <jakub@redhat.com>
Tue, 2 Jul 2024 20:08:45 +0000 (22:08 +0200)
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  <jakub@redhat.com>
    Jason Merrill  <jason@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.

gcc/cp/init.cc
gcc/testsuite/g++.dg/cpp26/delete1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp26/delete2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp26/delete3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/delete1.C
gcc/testsuite/g++.dg/ipa/pr85607.C
gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C
gcc/testsuite/g++.dg/warn/incomplete1.C

index 4a7ed7f53027516174bfc948360591fa3703ee18..826a31c4a84e8c4b9c59c28869fcd15c4493ac7a 100644 (file)
@@ -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 (file)
index 0000000..ca7766a
--- /dev/null
@@ -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 (file)
index 0000000..c5a6acf
--- /dev/null
@@ -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 (file)
index 0000000..d6702b7
--- /dev/null
@@ -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;
+};
index 617c7ba8a101ce8d6edcc56eb230bbe82bb8618c..f7c6257cfe46bb465981d2fdf788d0525eece037 100644 (file)
@@ -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 }
 }
index 9f6190961522e80691145da894894154f152b1fd..51000c05c30f43518e6ad191d761777781ef8ce4 100644 (file)
@@ -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;
 }
index d0c40e23db93f62f6508f993a994a133a8f83189..8be3446c06a80d39a6ecb7017c51854bb42297d7 100644 (file)
@@ -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 }
 }
index aa44c7ba3fb76bb4c7e9f66bb9a89d6f3a5d6596..f9e2edd224b543484192e63b908dca173b14641f 100644 (file)
 
 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;
 }