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

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Sun Aug 25 07:33:09 PDT 2024


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

>From eba7eb7c2258a424c0c45c4d5c9daadae92dc3e7 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] [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               |  2 +-
 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(+), 37 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..df0ee91343bd79 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  (`Github <https://github.com/llvm/llvm-project/issues/105427>`__)
 
 
 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..5ddeff7032ebcf 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 b8bad696f1bae0..90421d00019940 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 b041b08f02aac5..40df416a929097 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",



More information about the libcxx-commits mailing list