Skip to content

[libc++] P2747R2: constexpr placement new (library part) #105768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 28, 2024

Conversation

frederick-vs-ja
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja commented Aug 23, 2024

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 changes are not available for MS ABI because the operator new and operator new[] are from VCRuntime's <vcruntime_new.h>.

Notes for actual placement-new in constant evaluation:

Drive-by: Formatting the whole new.pass.cpp and new_array.pass.cpp.

Closes #105427.

@frederick-vs-ja frederick-vs-ja requested a review from a team as a code owner August 23, 2024 02:08
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Aug 23, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 23, 2024

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

Changes

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 (pending on #97957).

Drive-by: Formatting the whole new.pass.cpp and new_array.pass.cpp.

Closes #105427.


Full diff: https://github.com/llvm/llvm-project/pull/105768.diff

12 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1)
  • (modified) libcxx/docs/ReleaseNotes/20.rst (+1-1)
  • (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
  • (modified) libcxx/include/__config (+6)
  • (modified) libcxx/include/new (+8-2)
  • (modified) libcxx/include/version (+1-1)
  • (modified) libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new.pass.cpp (+21-10)
  • (modified) libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.placement/new_array.pass.cpp (+25-14)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/new.version.compile.pass.cpp (+5-11)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+5-11)
  • (modified) libcxx/test/support/test_macros.h (+6)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (-1)
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..3e48a3634533a5 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_CXX26 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 == '*');
+}
+
+#if TEST_STD_VER >= 26
+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..d318e338185c7e 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_CXX26 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 == '*');
+}
+
+#if TEST_STD_VER >= 26
+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..b52baaeaf139a9 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) \
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",

@@ -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",""
Copy link
Contributor Author

@frederick-vs-ja frederick-vs-ja Aug 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add some notes that only the library part is implemented?

Edit: Possibly no, as the compiler changes will be done soon are already complete.

@frederick-vs-ja frederick-vs-ja force-pushed the p2747r2 branch 3 times, most recently from aaf423b to 55f75d8 Compare August 23, 2024 09:15
@@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a check for __cpp_constexpr >= 202406L here too? constexpr operator new has been valid since C++23 but isn't usable without compiler support, and users might check defined(__cpp_lib_constexpr_new) instead of defined(__cpp_lib_constexpr_new) && __cpp_constexpr >= 202406L

Copy link
Contributor Author

@frederick-vs-ja frederick-vs-ja Aug 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a check for __cpp_constexpr >= 202406L here too? constexpr operator new has been valid since C++23 but isn't usable without compiler support,

I'm pretty sure that constexpr operator new in this paper doesn't require any constexpr feature after C++11. So the library changes don't require any change in the compiler.

and users might check defined(__cpp_lib_constexpr_new) instead of defined(__cpp_lib_constexpr_new) && __cpp_constexpr >= 202406L

I don't think it's meaningful to check __cpp_lib_constexpr_new. The approach for the core part in #104586 doesn't require library changes.

In other words, under Clang's current approach for constexpr placement new, the core and library changes are independent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your right, I was thinking that operator new could never be called in a constant expression, which might have been ill-formed NDR before C++23, but I forgot it could just be called directly operator new(1zu, p) without a new-expression. Which I guess is the only thing this patch adds support for with clang.

Looks like the GCC implementation does check if operator new is marked constexpr: https://godbolt.org/z/hYaYYvaKc so this is needed for GCC at least.

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`.
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM but I have a few questions.

@ldionne ldionne merged commit 7808541 into llvm:main Aug 28, 2024
3 of 5 checks passed
@frederick-vs-ja frederick-vs-ja deleted the p2747r2 branch August 28, 2024 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

P2747R2: constexpr placement new
4 participants