aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-07-02 22:08:45 +0200
committerJakub Jelinek <jakub@redhat.com>2024-07-02 22:08:45 +0200
commitbeb7a418aaef2ec8a812712110b007c091a73491 (patch)
tree088bc7eefe435ab66e20bc74bb34fe987f72a559
parentf30bdb1f2d79fd787e0c270039179bf80830161f (diff)
downloadgcc-beb7a418aaef2ec8a812712110b007c091a73491.zip
gcc-beb7a418aaef2ec8a812712110b007c091a73491.tar.gz
gcc-beb7a418aaef2ec8a812712110b007c091a73491.tar.bz2
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 <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.
-rw-r--r--gcc/cp/init.cc38
-rw-r--r--gcc/testsuite/g++.dg/cpp26/delete1.C36
-rw-r--r--gcc/testsuite/g++.dg/cpp26/delete2.C36
-rw-r--r--gcc/testsuite/g++.dg/cpp26/delete3.C36
-rw-r--r--gcc/testsuite/g++.dg/init/delete1.C7
-rw-r--r--gcc/testsuite/g++.dg/ipa/pr85607.C7
-rw-r--r--gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C7
-rw-r--r--gcc/testsuite/g++.dg/warn/incomplete1.C7
8 files changed, 160 insertions, 14 deletions
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 4a7ed7f..826a31c 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 0000000..ca7766a
--- /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 0000000..c5a6acf
--- /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 0000000..d6702b7
--- /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 617c7ba..f7c6257c 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 9f61909..51000c0 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 d0c40e2..8be3446 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 aa44c7b..f9e2edd 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;
}