[libcxx-commits] [libcxx] [libc++] P2747R2: `constexpr` placement new (library part) (PR #105768)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Thu Aug 22 20:50:45 PDT 2024


https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/105768

>From ef3f3c9f9c29410c0e25a48470e416ef01a3df02 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Fri, 23 Aug 2024 11:49:15 +0800
Subject: [PATCH] [libc++] P2747R2: `constexpr` placement new (library part)

Paper link: https://wg21.link/P2747R2

The library changes affect direct `operator new` and `operator new[]`
calls even when the core language changes are absent. "Actual"
placement new tests are not added yet as the core language changes
haven't been implemented.

The changes are not available for MS ABI because the `operator new` and
`operator new[]` are from VCRuntime's `<vcruntime_new.h>`.

Drive-by: formatting the whole `new.pass.cpp` and `new_array.pass.cpp`.
---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/ReleaseNotes/20.rst               |  2 +-
 libcxx/docs/Status/Cxx2cPapers.csv            |  2 +-
 libcxx/include/__config                       |  6 +++
 libcxx/include/new                            | 10 ++++-
 libcxx/include/version                        |  2 +-
 .../new.delete.placement/new.pass.cpp         | 31 ++++++++++-----
 .../new.delete.placement/new_array.pass.cpp   | 39 ++++++++++++-------
 .../new.version.compile.pass.cpp              | 16 +++-----
 .../version.version.compile.pass.cpp          | 16 +++-----
 libcxx/test/support/test_macros.h             | 15 +++++++
 .../generate_feature_test_macro_components.py |  1 -
 12 files changed, 89 insertions(+), 53 deletions(-)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index a1506e115fe70f..8a429ddd476010 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -404,7 +404,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_bitset``                                       ``202306L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_new``                                *unimplemented*
+    ``__cpp_lib_constexpr_new``                                ``202406L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_constrained_equality``                         *unimplemented*
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index fe9f4c1973cdb4..d048ab32d1f130 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -38,7 +38,7 @@ What's New in Libc++ 20.0.0?
 Implemented Papers
 ------------------
 
-- TODO
+- P2747R2 - ``constexpr`` placement new
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index dd62bcc2555ffc..bfb5e34da458d4 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -63,7 +63,7 @@
 "`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
 "`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19.0",""
 "","","","","",""
-"`P2747R2 <https://wg21.link/P2747R2>`__","``constexpr`` placement new","2024-06 (St. Louis)","","",""
+"`P2747R2 <https://wg21.link/P2747R2>`__","``constexpr`` placement new","2024-06 (St. Louis)","|Complete|","20.0",""
 "`P2997R1 <https://wg21.link/P2997R1>`__","Removing the common reference requirement from the indirectly invocable concepts","2024-06 (St. Louis)","|Complete| [#note-P2997R1]_","19.0",""
 "`P2389R2 <https://wg21.link/P2389R2>`__","``dextents`` Index Type Parameter","2024-06 (St. Louis)","|Complete|","19.0",""
 "`P3168R2 <https://wg21.link/P3168R2>`__","Give ``std::optional`` Range Support","2024-06 (St. Louis)","","","|ranges|"
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 392053a64a8dc1..9dd8d46b48d28f 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -788,6 +788,12 @@ typedef __char32_t char32_t;
 #    define _LIBCPP_CONSTEXPR_SINCE_CXX23
 #  endif
 
+#  if _LIBCPP_STD_VER >= 26
+#    define _LIBCPP_CONSTEXPR_SINCE_CXX26 constexpr
+#  else
+#    define _LIBCPP_CONSTEXPR_SINCE_CXX26
+#  endif
+
 #  ifndef _LIBCPP_WEAK
 #    define _LIBCPP_WEAK __attribute__((__weak__))
 #  endif
diff --git a/libcxx/include/new b/libcxx/include/new
index 214dbc398530bb..dc48cf44a3e7a2 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -242,8 +242,14 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::size_t __sz,
 #    endif
 #  endif
 
-_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI void* operator new(std::size_t, void* __p) _NOEXCEPT { return __p; }
-_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI void* operator new[](std::size_t, void* __p) _NOEXCEPT { return __p; }
+_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void*
+operator new(std::size_t, void* __p) _NOEXCEPT {
+  return __p;
+}
+_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void*
+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 {}
 
diff --git a/libcxx/include/version b/libcxx/include/version
index fe64343eafbc9c..aeddda625fc960 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -510,7 +510,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # undef  __cpp_lib_bind_front
 # define __cpp_lib_bind_front                           202306L
 # define __cpp_lib_bitset                               202306L
-// # define __cpp_lib_constexpr_new                        202406L
+# define __cpp_lib_constexpr_new                        202406L
 // # define __cpp_lib_constrained_equality                 202403L
 // # define __cpp_lib_copyable_function                    202306L
 // # define __cpp_lib_debugging                            202311L
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 b857b397fc83e4..330858ccf06816 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
@@ -15,19 +15,30 @@
 
 int A_constructed = 0;
 
-struct A
-{
-    A() {++A_constructed;}
-    ~A() {--A_constructed;}
+struct A {
+  A() { ++A_constructed; }
+  ~A() { --A_constructed; }
 };
 
-int main(int, char**)
-{
-    char buf[sizeof(A)];
+TEST_CONSTEXPR_OPERATOR_NEW void test_direct_call() {
+  assert(::operator new(sizeof(int), &A_constructed) == &A_constructed);
 
-    A* ap = new(buf) A;
-    assert((char*)ap == buf);
-    assert(A_constructed == 1);
+  char ch = '*';
+  assert(::operator new(1, &ch) == &ch);
+  assert(ch == '*');
+}
+
+#ifdef TEST_HAS_CONSTEXPR_OPERATOR_NEW
+static_assert((test_direct_call(), true));
+#endif
+
+int main(int, char**) {
+  char buf[sizeof(A)];
+
+  A* ap = new (buf) A;
+  assert((char*)ap == buf);
+  assert(A_constructed == 1);
 
+  test_direct_call();
   return 0;
 }
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 99a5442b6fb1f8..2fec815e3dbd7a 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
@@ -15,23 +15,34 @@
 
 int A_constructed = 0;
 
-struct A
-{
-    A() {++A_constructed;}
-    ~A() {--A_constructed;}
+struct A {
+  A() { ++A_constructed; }
+  ~A() { --A_constructed; }
 };
 
-int main(int, char**)
-{
-    const std::size_t Size = 3;
-    // placement new might require additional space.
-    const std::size_t ExtraSize = 64;
-    char buf[Size*sizeof(A) + ExtraSize];
+TEST_CONSTEXPR_OPERATOR_NEW void test_direct_call() {
+  assert(::operator new[](sizeof(int), &A_constructed) == &A_constructed);
 
-    A* ap = new(buf) A[Size];
-    assert((char*)ap >= buf);
-    assert((char*)ap < (buf + ExtraSize));
-    assert(A_constructed == Size);
+  char ch = '*';
+  assert(::operator new[](1, &ch) == &ch);
+  assert(ch == '*');
+}
+
+#ifdef TEST_HAS_CONSTEXPR_OPERATOR_NEW
+static_assert((test_direct_call(), true));
+#endif
+
+int main(int, char**) {
+  const std::size_t Size = 3;
+  // placement new might require additional space.
+  const std::size_t ExtraSize = 64;
+  char buf[Size * sizeof(A) + ExtraSize];
+
+  A* ap = new (buf) A[Size];
+  assert((char*)ap >= buf);
+  assert((char*)ap < (buf + ExtraSize));
+  assert(A_constructed == Size);
 
+  test_direct_call();
   return 0;
 }
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/new.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/new.version.compile.pass.cpp
index 17c1bd71eee675..e6308ae36085ca 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/new.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/new.version.compile.pass.cpp
@@ -171,17 +171,11 @@
 
 #elif TEST_STD_VER > 23
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_new
-#     error "__cpp_lib_constexpr_new should be defined in c++26"
-#   endif
-#   if __cpp_lib_constexpr_new != 202406L
-#     error "__cpp_lib_constexpr_new should have the value 202406L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_new
-#     error "__cpp_lib_constexpr_new should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_new
+#   error "__cpp_lib_constexpr_new should be defined in c++26"
+# endif
+# if __cpp_lib_constexpr_new != 202406L
+#   error "__cpp_lib_constexpr_new should have the value 202406L in c++26"
 # endif
 
 # if TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index b8bad696f1bae0..4ddd35ddff23f1 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -6554,17 +6554,11 @@
 #   error "__cpp_lib_constexpr_memory should have the value 202202L in c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_new
-#     error "__cpp_lib_constexpr_new should be defined in c++26"
-#   endif
-#   if __cpp_lib_constexpr_new != 202406L
-#     error "__cpp_lib_constexpr_new should have the value 202406L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_new
-#     error "__cpp_lib_constexpr_new should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_new
+#   error "__cpp_lib_constexpr_new should be defined in c++26"
+# endif
+# if __cpp_lib_constexpr_new != 202406L
+#   error "__cpp_lib_constexpr_new should have the value 202406L in c++26"
 # endif
 
 # ifndef __cpp_lib_constexpr_numeric
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index e96208c85d1d24..e465d3d9d1ed8e 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -184,6 +184,12 @@
 #  define TEST_CONSTEXPR_CXX23
 #endif
 
+#if TEST_STD_VER >= 26
+#  define TEST_CONSTEXPR_CXX26 constexpr
+#else
+#  define TEST_CONSTEXPR_CXX26
+#endif
+
 #define TEST_ALIGNAS_TYPE(...) TEST_ALIGNAS(TEST_ALIGNOF(__VA_ARGS__))
 
 #if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cpp_rtti) \
@@ -497,4 +503,13 @@ inline Tp const& DoNotOptimize(Tp const& value) {
 #  define TEST_HAS_EXPLICIT_THIS_PARAMETER
 #endif
 
+// Placement `operator new`/`operator new[]` are not yet constexpr in C++26
+// when using MS ABI, because they are from <vcruntime_new.h>.
+#if TEST_STD_VER >= 26 && !defined(TEST_ABI_MICROSOFT)
+#  define TEST_HAS_CONSTEXPR_OPERATOR_NEW
+#  define TEST_CONSTEXPR_OPERATOR_NEW constexpr
+#else
+#  define TEST_CONSTEXPR_OPERATOR_NEW
+#endif
+
 #endif // SUPPORT_TEST_MACROS_HPP
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index b041b08f02aac5..a4404380851578 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -363,7 +363,6 @@ def add_version_header(tc):
             "name": "__cpp_lib_constexpr_new",
             "values": {"c++26": 202406},  # P2747R2 constexpr placement new
             "headers": ["new"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_constexpr_numeric",



More information about the libcxx-commits mailing list