Author: Vlad Serebrennikov
Date: 2024-07-05T22:27:04+04:00
New Revision: 788731cdbd732180639988c9589adbe63bb28afa

URL: 
https://github.com/llvm/llvm-project/commit/788731cdbd732180639988c9589adbe63bb28afa
DIFF: 
https://github.com/llvm/llvm-project/commit/788731cdbd732180639988c9589adbe63bb28afa.diff

LOG: [clang] Implement P3144R2 "Deleting a Pointer to an Incomplete Type..." 
(#97733)

This patch implements (not yet published)
[P3144R2](https://wiki.edg.com/pub/Wg21stlouis2024/StrawPolls/p3144r2.pdf)
"Deleting a Pointer to an Incomplete Type Should be Ill-formed". Wording
changes (not yet merged into the working draft) read:
> 7.6.2.9 [expr.delete] Delete
> If the object being deleted has incomplete class type at the point of
deletion <del>and the complete class has a
non-trivial destructor or a deallocation function, the behavior is
undefined</del>, <ins>the program is ill-formed</ins>.

We preserve status quo of emitting a warning when deleting a pointer to
incomplete type up to, and including, C++23, but make it ill-formed
since C++26. Same goes for deleting pointers to `void`, which has been
allowed as an extension.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/CXX/drs/cwg5xx.cpp
    clang/test/OpenMP/deferred-diags.cpp
    clang/test/SemaCXX/new-delete.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 36cf615a4287cc..f6431a76b38de5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -272,6 +272,7 @@ C++2c Feature Support
 
 - Implemented `P2809R3: Trivial infinite loops are not Undefined Behavior 
<https://wg21.link/P2809R3>`_.
 
+- Implemented `P3144R2 Deleting a Pointer to an Incomplete Type Should be 
Ill-formed <https://wg21.link/P3144R2>`_.
 
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -438,6 +439,9 @@ New Compiler Flags
   Matches MSVC behaviour by defining ``__STDC__`` to ``1`` when
   MSVC compatibility mode is used. It has no effect for C++ code.
 
+- ``-Wc++2c-compat`` group was added to help migrating existing codebases
+  to C++26.
+
 Deprecated Compiler Flags
 -------------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 9431eea1f6be22..1b25cf36dd4f81 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -420,6 +420,8 @@ def CXX20CompatPedantic : DiagGroup<"c++20-compat-pedantic",
 def : DiagGroup<"c++2a-compat", [CXX20Compat]>;
 def : DiagGroup<"c++2a-compat-pedantic", [CXX20CompatPedantic]>;
 
+def CXX26Compat : DiagGroup<"c++2c-compat", [DeleteIncomplete]>;
+
 def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
 def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
 def FourByteMultiChar : DiagGroup<"four-char-constants">;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3df64b2ecef1b2..44fd51ec9abc96 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7989,8 +7989,11 @@ def ext_delete_void_ptr_operand : ExtWarn<
 def err_ambiguous_delete_operand : Error<
   "ambiguous conversion of delete expression of type %0 to a pointer">;
 def warn_delete_incomplete : Warning<
-  "deleting pointer to incomplete type %0 may cause undefined behavior">,
+  "deleting pointer to incomplete type %0 is incompatible with C++2c"
+  " and may cause undefined behavior">,
   InGroup<DeleteIncomplete>;
+def err_delete_incomplete : Error<
+  "cannot delete pointer to incomplete type %0">;
 def err_delete_incomplete_class_type : Error<
   "deleting incomplete class type %0; no conversions to pointer type">;
 def err_delete_explicit_conversion : Error<

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 69074f92a0286b..fcf2189a308a86 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3719,8 +3719,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool 
UseGlobal,
       // The C++ standard bans deleting a pointer to a non-object type, which
       // effectively bans deletion of "void*". However, most compilers support
       // this, so we treat it as a warning unless we're in a SFINAE context.
-      Diag(StartLoc, diag::ext_delete_void_ptr_operand)
-        << Type << Ex.get()->getSourceRange();
+      // But we still prohibit this since C++26.
+      Diag(StartLoc, LangOpts.CPlusPlus26 ? diag::err_delete_incomplete
+                                          : diag::ext_delete_void_ptr_operand)
+          << (LangOpts.CPlusPlus26 ? Pointee : Type)
+          << Ex.get()->getSourceRange();
     } else if (Pointee->isFunctionType() || Pointee->isVoidType() ||
                Pointee->isSizelessType()) {
       return ExprError(Diag(StartLoc, diag::err_delete_operand)
@@ -3729,7 +3732,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool 
UseGlobal,
       // FIXME: This can result in errors if the definition was imported from a
       // module but is hidden.
       if (!RequireCompleteType(StartLoc, Pointee,
-                               diag::warn_delete_incomplete, Ex.get())) {
+                               LangOpts.CPlusPlus26
+                                   ? diag::err_delete_incomplete
+                                   : diag::warn_delete_incomplete,
+                               Ex.get())) {
         if (const RecordType *RT = PointeeElem->getAs<RecordType>())
           PointeeRD = cast<CXXRecordDecl>(RT->getDecl());
       }

diff  --git a/clang/test/CXX/drs/cwg5xx.cpp b/clang/test/CXX/drs/cwg5xx.cpp
index 9d890f981348a7..6a0bb7a1966693 100644
--- a/clang/test/CXX/drs/cwg5xx.cpp
+++ b/clang/test/CXX/drs/cwg5xx.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -std=c++98 %s 
-verify=expected,cxx98-11,cxx98-14,cxx98-17,cxx98 -fexceptions -fcxx-exceptions 
-pedantic-errors
-// RUN: %clang_cc1 -std=c++11 %s 
-verify=expected,cxx98-11,cxx98-14,cxx98-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++14 %s 
-verify=expected,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions 
-pedantic-errors
-// RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,since-cxx17,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions 
-pedantic-errors
-// RUN: %clang_cc1 -std=c++20 %s 
-verify=expected,since-cxx20,since-cxx17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++23 %s 
-verify=expected,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++98 %s 
-verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s 
-verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s 
-verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++20 %s 
-verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++23 %s 
-verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2c %s 
-verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 
 #if __cplusplus == 199711L
 #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
@@ -901,7 +902,8 @@ namespace cwg573 { // cwg573: no
   void *d = reinterpret_cast<void*>(c);
   // cxx98-error@-1 {{cast between pointer-to-function and pointer-to-object 
is an extension}}
   void f() { delete a; }
-  // expected-error@-1 {{cannot delete expression with pointer-to-'void' type 
'void *'}}
+  // cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 
'void *'}}
+  // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
   int n = d - a;
   // expected-error@-1 {{arithmetic on pointers to void}}
   // FIXME: This is ill-formed.
@@ -1238,11 +1240,13 @@ namespace cwg599 { // cwg599: partial
   struct V { operator int*(); operator Fn*(); };
   void f(void *p, void (*q)(), S s, T t, U u, V v) {
     delete p;
-    // expected-error@-1 {{cannot delete expression with pointer-to-'void' 
type 'void *'}}
+    // cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' 
type 'void *'}}
+    // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
     delete q;
     // expected-error@-1 {{cannot delete expression of type 'void (*)()'}}
     delete s;
-    // expected-error@-1 {{cannot delete expression with pointer-to-'void' 
type 'void *'}}
+    // cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' 
type 'void *'}}
+    // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
     delete t;
     // expected-error@-1 {{cannot delete expression of type 'T'}}
     // FIXME: This is valid, but is rejected due to a non-conforming GNU

diff  --git a/clang/test/OpenMP/deferred-diags.cpp 
b/clang/test/OpenMP/deferred-diags.cpp
index a12f80309344c6..e31b99b8c88e45 100644
--- a/clang/test/OpenMP/deferred-diags.cpp
+++ b/clang/test/OpenMP/deferred-diags.cpp
@@ -41,7 +41,7 @@ namespace TestDeleteIncompleteClassDefinition {
 struct a;
 struct b {
   b() {
-    delete c; // expected-warning {{deleting pointer to incomplete type 'a' 
may cause undefined behavior}}
+    delete c; // expected-warning {{deleting pointer to incomplete type 'a' is 
incompatible with C++2c and may cause undefined behavior}}
   }
   a *c;
 };

diff  --git a/clang/test/SemaCXX/new-delete.cpp 
b/clang/test/SemaCXX/new-delete.cpp
index 1a99c6aac604f5..ec6ad43476f944 100644
--- a/clang/test/SemaCXX/new-delete.cpp
+++ b/clang/test/SemaCXX/new-delete.cpp
@@ -1,8 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17,cxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s 
-triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c
 
 // FIXME Location is (frontend)
 // cxx17-note@*:* {{candidate function not viable: requires 2 arguments, but 3 
were provided}}
@@ -172,8 +174,12 @@ void bad_deletes()
 {
   delete 0; // expected-error {{cannot delete expression of type 'int'}}
   delete [0] (int*)0; // expected-error {{expected variable name or 'this' in 
lambda capture list}}
-  delete (void*)0; // expected-warning {{cannot delete expression with 
pointer-to-'void' type 'void *'}}
-  delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
+  delete (void*)0;
+  // cxx98-23-warning@-1 {{cannot delete expression with pointer-to-'void' 
type 'void *'}}
+  // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
+  delete (T*)0;
+  // cxx98-23-warning@-1 {{deleting pointer to incomplete type}}
+  // since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'T'}}
   ::S::delete (int*)0; // expected-error {{expected unqualified-id}}
 }
 
@@ -513,8 +519,10 @@ namespace DeleteIncompleteClass {
 
 namespace DeleteIncompleteClassPointerError {
   struct A; // expected-note {{forward declaration}}
-  void f(A *x) { 1+delete x; } // expected-warning {{deleting pointer to 
incomplete type}} \
-                               // expected-error {{invalid operands to binary 
expression}}
+  void f(A *x) { 1+delete x; }
+  // expected-error@-1 {{invalid operands to binary expression}}
+  // cxx98-23-warning@-2 {{deleting pointer to incomplete type}}
+  // since-cxx26-error@-3 {{cannot delete pointer to incomplete type 'A'}}
 }
 
 namespace PR10504 {

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index f12ce38ba3d79c..0c013e6d7cb58d 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -213,7 +213,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
   <td>Deleting a Pointer to an Incomplete Type Should be Ill-formed</td>
   <td><a href="https://wg21.link/P3144";>P3144R2</a></td>
-  <td class="none" align="center">No</td>
+  <td class="Unreleased" align="center">Clang 19</td>
  </tr>
  <tr>
   <td>Ordering of constraints involving fold expressions</td>


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to