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

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 27 23:21:04 PDT 2024


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

>From 354a87445e7761de58ca46cb0162950b31708335 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Sun, 25 Aug 2024 22:32:25 +0800
Subject: [PATCH 1/2] [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. The approach of
Clang for "actual" placement new in constant evaluation doesn't depend
on the library changes.

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               |  1 +
 libcxx/docs/Status/Cxx2cPapers.csv            |  2 +-
 libcxx/include/__config                       |  6 +++
 libcxx/include/new                            | 10 ++++-
 libcxx/include/version                        |  4 +-
 .../new.delete.placement/new.pass.cpp         | 31 ++++++++++-----
 .../new.delete.placement/new_array.pass.cpp   | 39 ++++++++++++-------
 .../new.version.compile.pass.cpp              |  6 +--
 .../version.version.compile.pass.cpp          |  6 +--
 libcxx/test/support/test_macros.h             | 14 +++++++
 .../generate_feature_test_macro_components.py |  3 +-
 12 files changed, 88 insertions(+), 36 deletions(-)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index f6d3142c1e2d3e..9387a0f88a6373 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 bc28f380945bc3..4edcf70a657fb8 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -38,6 +38,7 @@ What's New in Libc++ 20.0.0?
 Implemented Papers
 ------------------
 
+- P2747R2: ``constexpr`` placement new (`Github <https://github.com/llvm/llvm-project/issues/105427>`__)
 - P2985R0: A type trait for detecting virtual base classes (`Github <https://github.com/llvm/llvm-project/issues/105432>`__)
 
 
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index d95cb11f483c00..b0e47baa1e2759 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 a19be2d294afd3..375ca0273931e0 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -510,7 +510,9 @@ __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
+# if !defined(_LIBCPP_ABI_VCRUNTIME)
+#   define __cpp_lib_constexpr_new                      202406L
+# endif
 // # 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..55be3f72508da3 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 __cpp_lib_constexpr_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..e27fad95becb77 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 __cpp_lib_constexpr_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..18dae0e4db6c0d 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,16 +171,16 @@
 
 #elif TEST_STD_VER > 23
 
-# if !defined(_LIBCPP_VERSION)
+# if !defined(_LIBCPP_ABI_VCRUNTIME)
 #   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
+# else
 #   ifdef __cpp_lib_constexpr_new
-#     error "__cpp_lib_constexpr_new should not be defined because it is unimplemented in libc++!"
+#     error "__cpp_lib_constexpr_new should not be defined when the requirement '!defined(_LIBCPP_ABI_VCRUNTIME)' is not met!"
 #   endif
 # endif
 
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 bd2959d55dc20d..48a74774f9a55c 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,16 +6554,16 @@
 #   error "__cpp_lib_constexpr_memory should have the value 202202L in c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
+# if !defined(_LIBCPP_ABI_VCRUNTIME)
 #   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
+# else
 #   ifdef __cpp_lib_constexpr_new
-#     error "__cpp_lib_constexpr_new should not be defined because it is unimplemented in libc++!"
+#     error "__cpp_lib_constexpr_new should not be defined when the requirement '!defined(_LIBCPP_ABI_VCRUNTIME)' is not met!"
 #   endif
 # endif
 
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index e96208c85d1d24..6f7ec3aa0c1f9f 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,12 @@ 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 defined(__cpp_lib_constexpr_new) && __cpp_lib_constexpr_new >= 202406L
+#  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 f402d4de2275e5..0430ff08a6d9d3 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -363,7 +363,8 @@ def add_version_header(tc):
             "name": "__cpp_lib_constexpr_new",
             "values": {"c++26": 202406},  # P2747R2 constexpr placement new
             "headers": ["new"],
-            "unimplemented": True,
+            "test_suite_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",
+            "libcxx_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",
         },
         {
             "name": "__cpp_lib_constexpr_numeric",

>From 8263b3ba7dc6eb541869daaa5ec6080f21fe48c0 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Wed, 28 Aug 2024 14:20:46 +0800
Subject: [PATCH 2/2] Update synopsis comments to mention `constexpr`

---
 libcxx/include/new | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/new b/libcxx/include/new
index dc48cf44a3e7a2..9015c4e712763c 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -79,8 +79,8 @@ void  operator delete[](void* ptr, const std::nothrow_t&) noexcept;     // repla
 void  operator delete[](void* ptr, std::align_val_t alignment,
                         const std::nothrow_t&) noexcept;                // replaceable, C++17
 
-void* operator new  (std::size_t size, void* ptr) noexcept;             // nodiscard in C++20
-void* operator new[](std::size_t size, void* ptr) noexcept;             // nodiscard in C++20
+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;
 



More information about the libcxx-commits mailing list