diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-07-02 22:08:45 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2024-07-02 22:08:45 +0200 |
commit | beb7a418aaef2ec8a812712110b007c091a73491 (patch) | |
tree | 088bc7eefe435ab66e20bc74bb34fe987f72a559 /gcc | |
parent | f30bdb1f2d79fd787e0c270039179bf80830161f (diff) | |
download | gcc-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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/init.cc | 38 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/delete1.C | 36 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/delete2.C | 36 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/delete3.C | 36 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/delete1.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ipa/pr85607.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wdelete-incomplete-1.C | 7 | ||||
-rw-r--r-- | 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 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; } |