[libcxx-commits] [libcxx] 7cb66a4 - [libc++] Implement LWG4477: placement operator delete should be constexpr (#189915)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 8 06:48:38 PDT 2026


Author: Fernando Pelliccioni
Date: 2026-04-08T21:48:32+08:00
New Revision: 7cb66a448ace7ae2acd84e7e9bec73cfc560efe0

URL: https://github.com/llvm/llvm-project/commit/7cb66a448ace7ae2acd84e7e9bec73cfc560efe0
DIFF: https://github.com/llvm/llvm-project/commit/7cb66a448ace7ae2acd84e7e9bec73cfc560efe0.diff

LOG: [libc++] Implement LWG4477: placement operator delete should be constexpr (#189915)

Implement the proposed resolution of
[LWG4477](https://cplusplus.github.io/LWG/issue4477).

P2747R2 made placement `operator new` constexpr since C++26, but the
corresponding placement `operator delete` was not. When a constructor
throws during placement new in a constant expression, the placement
delete is invoked and fails because it's not constexpr.

Add `_LIBCPP_CONSTEXPR_SINCE_CXX26` to placement `operator delete(void*,
void*)` and `operator delete[](void*, void*)`.

Closes #189843

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx2cIssues.csv
    libcxx/include/__new/placement_new_delete.h
    libcxx/include/new
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new_array.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 75972e0b2874c..6f5af8eb9dbee 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -298,7 +298,7 @@
 "`LWG4472 <https://wg21.link/LWG4472>`__","``std::atomic_ref<const T>`` can be constructed from temporaries","2026-03 (Croydon)","","","`#189840 <https://github.com/llvm/llvm-project/issues/189840>`__",""
 "`LWG4474 <https://wg21.link/LWG4474>`__","""`round_to_nearest`"" rounding mode is unclear","2026-03 (Croydon)","","","`#189841 <https://github.com/llvm/llvm-project/issues/189841>`__",""
 "`LWG4476 <https://wg21.link/LWG4476>`__","``run_loop`` should not have a ``set_error`` completion","2026-03 (Croydon)","","","`#189842 <https://github.com/llvm/llvm-project/issues/189842>`__",""
-"`LWG4477 <https://wg21.link/LWG4477>`__","Placement ``operator delete`` should be constexpr","2026-03 (Croydon)","","","`#189843 <https://github.com/llvm/llvm-project/issues/189843>`__",""
+"`LWG4477 <https://wg21.link/LWG4477>`__","Placement ``operator delete`` should be constexpr","2026-03 (Croydon)","|Complete|","23","`#189843 <https://github.com/llvm/llvm-project/issues/189843>`__",""
 "`LWG4478 <https://wg21.link/LWG4478>`__","``meta::has_identifier`` is not specified for annotations","2026-03 (Croydon)","","","`#189844 <https://github.com/llvm/llvm-project/issues/189844>`__",""
 "`LWG4480 <https://wg21.link/LWG4480>`__","``<stdatomic.h>`` should provide ``ATOMIC_CHAR8_T_LOCK_FREE``","2026-03 (Croydon)","","","`#189845 <https://github.com/llvm/llvm-project/issues/189845>`__",""
 "`LWG4481 <https://wg21.link/LWG4481>`__","Disallow ``chrono::duration<const T, P>``","2026-03 (Croydon)","","","`#189846 <https://github.com/llvm/llvm-project/issues/189846>`__",""

diff  --git a/libcxx/include/__new/placement_new_delete.h b/libcxx/include/__new/placement_new_delete.h
index 42c9f34036775..74692f36fd04c 100644
--- a/libcxx/include/__new/placement_new_delete.h
+++ b/libcxx/include/__new/placement_new_delete.h
@@ -27,8 +27,8 @@ operator new(std::size_t, void* __p) _NOEXCEPT {
 operator new[](std::size_t, void* __p) _NOEXCEPT {
   return __p;
 }
-inline _LIBCPP_HIDE_FROM_ABI void operator delete(void*, void*) _NOEXCEPT {}
-inline _LIBCPP_HIDE_FROM_ABI void operator delete[](void*, void*) _NOEXCEPT {}
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void operator delete(void*, void*) _NOEXCEPT {}
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void operator delete[](void*, void*) _NOEXCEPT {}
 #endif
 
 #endif // _LIBCPP___NEW_PLACEMENT_NEW_DELETE_H

diff  --git a/libcxx/include/new b/libcxx/include/new
index 4d72ec27675c9..ef66c67ccfbcc 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -81,8 +81,8 @@ void  operator delete[](void* ptr, std::align_val_t alignment,
 
 void* operator new  (std::size_t size, void* ptr) noexcept;             // nodiscard in C++20, constexpr since C++26
 void* operator new[](std::size_t size, void* ptr) noexcept;             // nodiscard in C++20, constexpr since C++26
-void  operator delete  (void* ptr, void*) noexcept;
-void  operator delete[](void* ptr, void*) noexcept;
+void  operator delete  (void* ptr, void*) noexcept;                     // constexpr since C++26
+void  operator delete[](void* ptr, void*) noexcept;                     // constexpr since C++26
 
 */
 

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new.pass.cpp
index 55be3f72508da..8c4f06ad07bbe 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new.pass.cpp
@@ -25,7 +25,10 @@ TEST_CONSTEXPR_OPERATOR_NEW void test_direct_call() {
 
   char ch = '*';
   assert(::operator new(1, &ch) == &ch);
+  ::operator delete(&ch, &ch);
   assert(ch == '*');
+
+  ::operator delete(nullptr, nullptr);
 }
 
 #ifdef __cpp_lib_constexpr_new

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new_array.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new_array.pass.cpp
index 1f7b08ec641c3..675b0f65470e8 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new_array.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new_array.pass.cpp
@@ -26,7 +26,10 @@ TEST_CONSTEXPR_OPERATOR_NEW void test_direct_call() {
 
   char ch = '*';
   assert(::operator new[](1, &ch) == &ch);
+  ::operator delete[](&ch, &ch);
   assert(ch == '*');
+
+  ::operator delete[](nullptr, nullptr);
 }
 
 #ifdef __cpp_lib_constexpr_new


        


More information about the libcxx-commits mailing list