[libcxx-commits] [libcxx] 181cce6 - [libc++] Implement P0339R6 (polymorphic_allocator<> as a vocabulary type)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Dec 7 09:50:31 PST 2022


Author: Nikolas Klauser
Date: 2022-12-07T18:50:26+01:00
New Revision: 181cce6b696e032735fb3e3d23b1db1fb9fca5cb

URL: https://github.com/llvm/llvm-project/commit/181cce6b696e032735fb3e3d23b1db1fb9fca5cb
DIFF: https://github.com/llvm/llvm-project/commit/181cce6b696e032735fb3e3d23b1db1fb9fca5cb.diff

LOG: [libc++] Implement P0339R6 (polymorphic_allocator<> as a vocabulary type)

Reviewed By: ldionne, #libc

Spies: LRFLEW, libcxx-commits, arichardson, krytarowski, jdoerfert

Differential Revision: https://reviews.llvm.org/D137739

Added: 
    libcxx/test/libcxx/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_vocabulary.attributes.verify.cpp
    libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_bytes.pass.cpp
    libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_object.pass.cpp
    libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_vocabulary.nodiscard.verify.cpp
    libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/default_type.compile.pass.cpp
    libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/new_delete_object.pass.cpp
    libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/tracking_mem_res.h

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx20Issues.csv
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/include/__memory_resource/polymorphic_allocator.h
    libcxx/include/__type_traits/is_nothrow_constructible.h
    libcxx/include/__utility/transaction.h
    libcxx/include/experimental/iterator
    libcxx/include/version
    libcxx/test/libcxx/transitive_includes/cxx03.csv
    libcxx/test/libcxx/transitive_includes/cxx11.csv
    libcxx/test/libcxx/transitive_includes/cxx14.csv
    libcxx/test/libcxx/transitive_includes/cxx17.csv
    libcxx/test/libcxx/transitive_includes/cxx20.csv
    libcxx/test/libcxx/transitive_includes/cxx2b.csv
    libcxx/test/std/language.support/support.limits/support.limits.general/memory_resource.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 5ba070e7a1ea8..a1371267cd32b 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -260,7 +260,7 @@ Status
     ------------------------------------------------- -----------------
     ``__cpp_lib_math_constants``                      ``201907L``
     ------------------------------------------------- -----------------
-    ``__cpp_lib_polymorphic_allocator``               *unimplemented*
+    ``__cpp_lib_polymorphic_allocator``               ``201902L``
     ------------------------------------------------- -----------------
     ``__cpp_lib_ranges``                              ``201811L``
     ------------------------------------------------- -----------------

diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index f37751b72665f..a04eacbd4ba9f 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -48,6 +48,7 @@ Implemented Papers
 - P0482R6 - char8_t: A type for UTF-8 characters and strings
 - P2438R2 - ``std::string::substr() &&``
 - P0600R1 - ``nodiscard`` in the library
+- P0339R6 - ``polymorphic_allocator<>`` as a vocabulary type
 
 Improvements and New Features
 -----------------------------

diff  --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index d1ba4a167fc48..1a51daa0ec641 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -201,7 +201,7 @@
 "`3201 <https://wg21.link/LWG3201>`__","``lerp``\  should be marked as ``noexcept``\ ","Prague","|Complete|",""
 "`3226 <https://wg21.link/LWG3226>`__","``zoned_time``\  constructor from ``string_view``\  should accept ``zoned_time<Duration2, TimeZonePtr2>``\ ","Prague","","","|chrono|"
 "`3233 <https://wg21.link/LWG3233>`__","Broken requirements for ``shared_ptr``\  converting constructors","Prague","",""
-"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","14.0"
+"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","16.0"
 "`3238 <https://wg21.link/LWG3238>`__","Insufficiently-defined behavior of ``std::function``\  deduction guides","Prague","",""
 "`3242 <https://wg21.link/LWG3242>`__","``std::format``\ : missing rules for ``arg-id``\  in ``width``\  and ``precision``\ ","Prague","|Complete|","Clang 14","|format|"
 "`3243 <https://wg21.link/LWG3243>`__","``std::format``\  and negative zeroes","Prague","|Complete|","14.0","|format|"
@@ -232,9 +232,9 @@
 "`3301 <https://wg21.link/LWG3301>`__","``transform_view::iterator``\  has incorrect ``iterator_category``\ ","Prague","|Complete|","15.0","|ranges|"
 "`3302 <https://wg21.link/LWG3302>`__","Range adaptor objects ``keys``\  and ``values``\  are unspecified","Prague","","","|ranges|"
 "`3303 <https://wg21.link/LWG3303>`__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","Prague","",""
-"`3304 <https://wg21.link/LWG3304>`__","Allocate functions of ``std::polymorphic_allocator``\  should require ``[[nodiscard]]``\ ","Prague","",""
+"`3304 <https://wg21.link/LWG3304>`__","Allocate functions of ``std::polymorphic_allocator``\  should require ``[[nodiscard]]``\ ","Prague","|Complete|","16.0"
 "`3307 <https://wg21.link/LWG3307>`__","``std::allocator<void>().allocate(n)``\ ","Prague","",""
-"`3310 <https://wg21.link/LWG3310>`__","Replace ``SIZE_MAX``\  with ``numeric_limits<size_t>::max()``\ ","Prague","",""
+"`3310 <https://wg21.link/LWG3310>`__","Replace ``SIZE_MAX``\  with ``numeric_limits<size_t>::max()``\ ","Prague","|Complete|","16.0"
 "`3313 <https://wg21.link/LWG3313>`__","``join_view::iterator::operator--``\  is incorrectly constrained","Prague","|Complete|","14.0","|ranges|"
 "`3314 <https://wg21.link/LWG3314>`__","Is stream insertion behavior locale dependent when ``Period::type``\  is ``micro``\ ?","Prague","|Complete|","16.0","|chrono|"
 "`3315 <https://wg21.link/LWG3315>`__","Correct Allocator Default Behavior","Prague","",""

diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 70f13a902f9fb..95e3c4cc51493 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -80,7 +80,7 @@
 "`P1285R0 <https://wg21.link/P1285R0>`__","LWG","Improving Completeness Requirements for Type Traits","San Diego","* *",""
 "`P1353R0 <https://wg21.link/P1353R0>`__","CWG","Missing feature test macros","San Diego","* *",""
 "","","","","",""
-"`P0339R6 <https://wg21.link/P0339R6>`__","LWG","polymorphic_allocator<> as a vocabulary type","Kona","",""
+"`P0339R6 <https://wg21.link/P0339R6>`__","LWG","polymorphic_allocator<> as a vocabulary type","Kona","|Complete|","16.0"
 "`P0340R3 <https://wg21.link/P0340R3>`__","LWG","Making std::underlying_type SFINAE-friendly","Kona","|Complete|","9.0"
 "`P0738R2 <https://wg21.link/P0738R2>`__","LWG","I Stream, You Stream, We All Stream for istream_iterator","Kona","",""
 "`P0811R3 <https://wg21.link/P0811R3>`__","LWG","Well-behaved interpolation for numbers and pointers","Kona","|Complete|","9.0"

diff  --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h
index a5ca39b57e69d..8e59dfc55d78c 100644
--- a/libcxx/include/__memory_resource/polymorphic_allocator.h
+++ b/libcxx/include/__memory_resource/polymorphic_allocator.h
@@ -12,6 +12,7 @@
 #include <__assert>
 #include <__config>
 #include <__memory_resource/memory_resource.h>
+#include <__utility/transaction.h>
 #include <cstddef>
 #include <limits>
 #include <new>
@@ -33,8 +34,13 @@ namespace pmr {
 
 // [mem.poly.allocator.class]
 
-template <class _ValueType>
+template <class _ValueType
+#  if _LIBCPP_STD_VER >= 20
+          = byte
+#  endif
+          >
 class _LIBCPP_TEMPLATE_VIS polymorphic_allocator {
+
 public:
   using value_type = _ValueType;
 
@@ -66,6 +72,46 @@ class _LIBCPP_TEMPLATE_VIS polymorphic_allocator {
     __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));
   }
 
+#  if _LIBCPP_STD_VER >= 20
+
+  [[nodiscard]] [[using __gnu__: __alloc_size__(2), __alloc_align__(3)]] void*
+  allocate_bytes(size_t __nbytes, size_t __alignment = alignof(max_align_t)) {
+    return __res_->allocate(__nbytes, __alignment);
+  }
+
+  void deallocate_bytes(void* __ptr, size_t __nbytes, size_t __alignment = alignof(max_align_t)) {
+    __res_->deallocate(__ptr, __nbytes, __alignment);
+  }
+
+  template <class _Type>
+  [[nodiscard]] _Type* allocate_object(size_t __n = 1) {
+    if (numeric_limits<size_t>::max() / sizeof(_Type) < __n)
+      std::__throw_bad_array_new_length();
+    return static_cast<_Type*>(allocate_bytes(__n * sizeof(_Type), alignof(_Type)));
+  }
+
+  template <class _Type>
+  void deallocate_object(_Type* __ptr, size_t __n = 1) {
+    deallocate_bytes(__ptr, __n * sizeof(_Type), alignof(_Type));
+  }
+
+  template <class _Type, class... _CtorArgs>
+  [[nodiscard]] _Type* new_object(_CtorArgs&&... __ctor_args) {
+    _Type* __ptr = allocate_object<_Type>();
+    __transaction __guard([&] { deallocate_object(__ptr); });
+    construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...);
+    __guard.__complete();
+    return __ptr;
+  }
+
+  template <class _Type>
+  void delete_object(_Type* __ptr) {
+    destroy(__ptr);
+    deallocate_object(__ptr);
+  }
+
+#  endif // _LIBCPP_STD_VER >= 20
+
   template <class _Tp, class... _Ts>
   _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) {
     std::__user_alloc_construct_impl(

diff  --git a/libcxx/include/__type_traits/is_nothrow_constructible.h b/libcxx/include/__type_traits/is_nothrow_constructible.h
index 6dc6ccd450d88..6272298889be8 100644
--- a/libcxx/include/__type_traits/is_nothrow_constructible.h
+++ b/libcxx/include/__type_traits/is_nothrow_constructible.h
@@ -11,6 +11,9 @@
 
 #include <__config>
 #include <__type_traits/integral_constant.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_reference.h>
+#include <__utility/declval.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header

diff  --git a/libcxx/include/__utility/transaction.h b/libcxx/include/__utility/transaction.h
index dc65c349d13c7..3baedd2baf7b8 100644
--- a/libcxx/include/__utility/transaction.h
+++ b/libcxx/include/__utility/transaction.h
@@ -10,9 +10,9 @@
 #define _LIBCPP___UTILITY_TRANSACTION_H
 
 #include <__config>
+#include <__type_traits/is_nothrow_move_constructible.h>
 #include <__utility/exchange.h>
 #include <__utility/move.h>
-#include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header

diff  --git a/libcxx/include/experimental/iterator b/libcxx/include/experimental/iterator
index 3e460d6a7f5db..399365ed0c744 100644
--- a/libcxx/include/experimental/iterator
+++ b/libcxx/include/experimental/iterator
@@ -118,4 +118,8 @@ _LIBCPP_END_NAMESPACE_LFTS
 
 #endif // _LIBCPP_STD_VER > 11
 
+#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
+#  include <type_traits>
+#endif
+
 #endif // _LIBCPP_EXPERIMENTAL_ITERATOR

diff  --git a/libcxx/include/version b/libcxx/include/version
index 5e2b8cd43a998..9443564b0466b 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -354,7 +354,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # endif
 # define __cpp_lib_list_remove_return_type              201806L
 # define __cpp_lib_math_constants                       201907L
-// # define __cpp_lib_polymorphic_allocator                201902L
+# define __cpp_lib_polymorphic_allocator                201902L
 # define __cpp_lib_ranges                               201811L
 # define __cpp_lib_remove_cvref                         201711L
 # if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index e6dcd70c25087..c3eff22f1fee6 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -556,6 +556,7 @@ memory_resource mutex
 memory_resource new
 memory_resource stdexcept
 memory_resource tuple
+memory_resource type_traits
 memory_resource version
 mutex atomic
 mutex concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 34c2f0f0e8877..0ab039f113f14 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -556,6 +556,7 @@ memory_resource mutex
 memory_resource new
 memory_resource stdexcept
 memory_resource tuple
+memory_resource type_traits
 memory_resource version
 mutex atomic
 mutex concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 3f4f7879faa59..491b28707c291 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -558,6 +558,7 @@ memory_resource mutex
 memory_resource new
 memory_resource stdexcept
 memory_resource tuple
+memory_resource type_traits
 memory_resource version
 mutex atomic
 mutex concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 3f4f7879faa59..491b28707c291 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -558,6 +558,7 @@ memory_resource mutex
 memory_resource new
 memory_resource stdexcept
 memory_resource tuple
+memory_resource type_traits
 memory_resource version
 mutex atomic
 mutex concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 6462223d630e8..1f3798909e533 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -569,6 +569,7 @@ memory_resource mutex
 memory_resource new
 memory_resource stdexcept
 memory_resource tuple
+memory_resource type_traits
 memory_resource version
 mutex atomic
 mutex concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
index 18803bc804d3b..bcc949bc4233a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
@@ -438,6 +438,7 @@ memory_resource mutex
 memory_resource new
 memory_resource stdexcept
 memory_resource tuple
+memory_resource type_traits
 memory_resource version
 mutex atomic
 mutex cstddef

diff  --git a/libcxx/test/libcxx/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_vocabulary.attributes.verify.cpp b/libcxx/test/libcxx/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_vocabulary.attributes.verify.cpp
new file mode 100644
index 0000000000000..d5cd62ec28b2a
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_vocabulary.attributes.verify.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// check that clang warns on non-power-of-two alignment
+
+#include <memory_resource>
+
+void func() {
+  std::pmr::polymorphic_allocator<> allocator;
+  (void)allocator.allocate_bytes(0, 3); // expected-warning {{requested alignment is not a power of 2}}
+
+}

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory_resource.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory_resource.version.compile.pass.cpp
index 53f5e5c38210a..573fd0fbc0a3c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory_resource.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory_resource.version.compile.pass.cpp
@@ -65,17 +65,11 @@
 #   error "__cpp_lib_memory_resource should have the value 201603L in c++20"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should be defined in c++20"
-#   endif
-#   if __cpp_lib_polymorphic_allocator != 201902L
-#     error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_polymorphic_allocator
+#   error "__cpp_lib_polymorphic_allocator should be defined in c++20"
+# endif
+# if __cpp_lib_polymorphic_allocator != 201902L
+#   error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
 # endif
 
 #elif TEST_STD_VER > 20
@@ -87,17 +81,11 @@
 #   error "__cpp_lib_memory_resource should have the value 201603L in c++2b"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
-#   endif
-#   if __cpp_lib_polymorphic_allocator != 201902L
-#     error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_polymorphic_allocator
+#   error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
+# endif
+# if __cpp_lib_polymorphic_allocator != 201902L
+#   error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
 # endif
 
 #endif // TEST_STD_VER > 20

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 971bb22523ab1..50632e68e1d66 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
@@ -3208,17 +3208,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should be defined in c++20"
-#   endif
-#   if __cpp_lib_polymorphic_allocator != 201902L
-#     error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_polymorphic_allocator
+#   error "__cpp_lib_polymorphic_allocator should be defined in c++20"
+# endif
+# if __cpp_lib_polymorphic_allocator != 201902L
+#   error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
 # endif
 
 # ifndef __cpp_lib_quoted_string_io
@@ -4478,17 +4472,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
-#   endif
-#   if __cpp_lib_polymorphic_allocator != 201902L
-#     error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_polymorphic_allocator
-#     error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_polymorphic_allocator
+#   error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
+# endif
+# if __cpp_lib_polymorphic_allocator != 201902L
+#   error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
 # endif
 
 # ifndef __cpp_lib_quoted_string_io

diff  --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_bytes.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_bytes.pass.cpp
new file mode 100644
index 0000000000000..a4db295f9ac32
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_bytes.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{11.0|12.0}}
+
+// test_memory_resource requires RTTI for dynamic_cast
+// UNSUPPORTED: no-rtti
+
+// <memory_resource>
+
+// polymorphic_allocator::allocate_bytes()
+// polymorphic_allocator::deallocate_bytes()
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <memory_resource>
+
+#include "tracking_mem_res.h"
+
+template <class T>
+void test() {
+  size_t last_size      = 0;
+  size_t last_alignment = 0;
+  TrackingMemRes resource(&last_size, &last_alignment);
+
+  std::pmr::polymorphic_allocator<T> allocator(&resource);
+
+  {
+    std::same_as<void*> decltype(auto) allocation = allocator.allocate_bytes(13);
+    auto ptr                                      = static_cast<char*>(allocation);
+    std::fill(ptr, ptr + 13, '0');
+    assert(last_size == 13);
+    assert(last_alignment == alignof(max_align_t));
+    allocator.deallocate_bytes(allocation, 13);
+    assert(last_size == 13);
+    assert(last_alignment == alignof(max_align_t));
+  }
+  {
+    void* allocation = allocator.allocate_bytes(13, 64);
+    auto ptr         = static_cast<char*>(allocation);
+    std::fill(ptr, ptr + 13, '0');
+    assert(last_size == 13);
+    assert(last_alignment == 64);
+    allocator.deallocate_bytes(allocation, 13, 64);
+    assert(last_size == 13);
+    assert(last_alignment == 64);
+  }
+}
+
+struct S {};
+
+int main(int, char**) {
+  test<std::byte>();
+  test<S>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_object.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_object.pass.cpp
new file mode 100644
index 0000000000000..b061afbbae0f1
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_object.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{11.0|12.0}}
+
+// test_memory_resource requires RTTI for dynamic_cast
+// UNSUPPORTED: no-rtti
+
+// <memory_resource>
+
+// polymorphic_allocator::allocate_object()
+// polymorphic_allocator::deallocate_object()
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <memory_resource>
+
+#include "tracking_mem_res.h"
+
+template <class T>
+void test() {
+  size_t last_size      = 0;
+  size_t last_alignment = 0;
+  TrackingMemRes resource(&last_size, &last_alignment);
+
+  std::pmr::polymorphic_allocator<T> allocator(&resource);
+
+  {
+    std::same_as<int*> decltype(auto) allocation = allocator.template allocate_object<int>();
+    std::fill(allocation, allocation + 1, 3);
+    assert(last_size == sizeof(int));
+    assert(last_alignment == alignof(int));
+    allocator.deallocate_object(allocation);
+    assert(last_size == sizeof(int));
+    assert(last_alignment == alignof(int));
+  }
+  {
+    int* allocation = allocator.template allocate_object<int>(3);
+    std::fill(allocation, allocation + 3, 3);
+    assert(last_size == sizeof(int) * 3);
+    assert(last_alignment == alignof(int));
+    allocator.deallocate_object(allocation, 3);
+    assert(last_size == sizeof(int) * 3);
+    assert(last_alignment == alignof(int));
+  }
+}
+
+struct S {};
+
+int main(int, char**) {
+  test<std::byte>();
+  test<S>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_vocabulary.nodiscard.verify.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_vocabulary.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..f3b0391d37619
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate_deallocate_vocabulary.nodiscard.verify.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// check that functions are marked [[nodiscard]]
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// test_memory_resource requires RTTI for dynamic_cast
+// UNSUPPORTED: no-rtti
+
+// <memory_resource>
+
+// polymorphic_allocator::allocate_bytes()
+// polymorphic_allocator::allocate_object()
+// polymorphic_allocator::new_object()
+
+#include <memory_resource>
+
+void func() {
+  std::pmr::polymorphic_allocator<> allocator;
+  allocator.allocate_bytes(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  allocator.allocate_object<int>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  allocator.new_object<int>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}

diff  --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/default_type.compile.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/default_type.compile.pass.cpp
new file mode 100644
index 0000000000000..67d552ca9d11d
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/default_type.compile.pass.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{11.0|12.0}}
+
+// test_memory_resource requires RTTI for dynamic_cast
+// UNSUPPORTED: no-rtti
+
+#include <memory_resource>
+#include <type_traits>
+
+static_assert(std::is_same_v<std::pmr::polymorphic_allocator<>, std::pmr::polymorphic_allocator<std::byte>>);

diff  --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/new_delete_object.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/new_delete_object.pass.cpp
new file mode 100644
index 0000000000000..463a8157e7233
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/new_delete_object.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{11.0|12.0}}
+
+// test_memory_resource requires RTTI for dynamic_cast
+// UNSUPPORTED: no-rtti
+
+// <memory_resource>
+
+// polymorphic_allocator::new_object()
+// polymorphic_allocator::delete_object()
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <memory_resource>
+
+#include "tracking_mem_res.h"
+
+template <class T>
+void test() {
+  size_t last_size      = 0;
+  size_t last_alignment = 0;
+  TrackingMemRes resource(&last_size, &last_alignment);
+
+  std::pmr::polymorphic_allocator<T> allocator(&resource);
+
+  {
+    std::same_as<int*> decltype(auto) allocation = allocator.template new_object<int>();
+    std::fill(allocation, allocation + 1, 4);
+    assert(last_size == sizeof(int));
+    assert(last_alignment == alignof(int));
+    allocator.delete_object(allocation);
+  }
+  {
+    std::same_as<int*> decltype(auto) allocation = allocator.template new_object<int>(3);
+    assert(*allocation == 3);
+    std::fill(allocation, allocation + 1, 4);
+    assert(last_size == sizeof(int));
+    assert(last_alignment == alignof(int));
+    allocator.delete_object(allocation);
+  }
+  {
+    struct TrackConstruction {
+      bool* is_constructed_;
+      TrackConstruction(bool* is_constructed) : is_constructed_(is_constructed) { *is_constructed = true; }
+      ~TrackConstruction() { *is_constructed_ = false; }
+    };
+
+    bool is_constructed = false;
+
+    std::same_as<TrackConstruction*> decltype(auto) allocation =
+        allocator.template new_object<TrackConstruction>(&is_constructed);
+    assert(is_constructed);
+    assert(last_size == sizeof(TrackConstruction));
+    assert(last_alignment == alignof(TrackConstruction));
+    allocator.delete_object(allocation);
+    assert(!is_constructed);
+  }
+}
+
+struct S {};
+
+int main(int, char**) {
+  test<std::byte>();
+  test<S>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/tracking_mem_res.h b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/tracking_mem_res.h
new file mode 100644
index 0000000000000..d0b9eab578092
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/tracking_mem_res.h
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TRACKING_MEM_RES_H
+#define TRACKING_MEM_RES_H
+
+#include <memory_resource>
+
+class TrackingMemRes : public std::pmr::memory_resource {
+public:
+  TrackingMemRes(size_t* last_size, size_t* last_alginment) : last_size_(last_size), last_alginment_(last_alginment) {}
+
+private:
+  size_t* last_size_;
+  size_t* last_alginment_;
+  void* do_allocate(size_t size, size_t alignment) override {
+    *last_size_      = size;
+    *last_alginment_ = alignment;
+
+    return std::pmr::new_delete_resource()->allocate(size, alignment);
+  }
+
+  void do_deallocate(void* ptr, size_t size, size_t alignment) override {
+    *last_size_      = size;
+    *last_alginment_ = alignment;
+    std::pmr::new_delete_resource()->deallocate(ptr, size, alignment);
+  }
+
+  bool do_is_equal(const memory_resource& ptr) const noexcept override { return &ptr == this; }
+};
+
+#endif // TRACKING_MEM_RES_H

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 85629e11755e4..81086993a5f49 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -525,7 +525,6 @@ def add_version_header(tc):
     "name": "__cpp_lib_polymorphic_allocator",
     "values": { "c++20": 201902 },
     "headers": ["memory_resource"],
-    "unimplemented": True,
   }, {
     "name": "__cpp_lib_quoted_string_io",
     "values": { "c++14": 201304 },


        


More information about the libcxx-commits mailing list