From 7d78ccf7d5a9861839126d5899b443f55236cab9 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 1 Feb 2024 13:31:25 +0200 Subject: [PATCH] [libc++][memory] P2652R2: Disallow Specialization of `allocator_traits` (#79978) Implements P2652R2 : - https://eel.is/c++draft/allocator.requirements.general - https://eel.is/c++draft/memory.syn - https://eel.is/c++draft/allocator.traits.general - https://eel.is/c++draft/allocator.traits.members - https://eel.is/c++draft/diff.cpp20.concepts - https://eel.is/c++draft/diff.cpp20.utilities --------- Co-authored-by: Zingam --- libcxx/docs/FeatureTestMacroTable.rst | 2 +- libcxx/docs/ReleaseNotes/19.rst | 2 ++ libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/docs/Status/Cxx2cIssues.csv | 2 +- libcxx/include/__memory/allocate_at_least.h | 20 +++------------- libcxx/include/__memory/allocator_traits.h | 24 +++++++++++++++++++ libcxx/include/memory | 13 +++++----- libcxx/include/version | 4 ++-- libcxx/modules/std/memory.inc | 2 -- .../memory.version.compile.pass.cpp | 10 ++++---- .../version.version.compile.pass.cpp | 10 ++++---- .../allocate_at_least.pass.cpp | 10 ++++---- .../generate_feature_test_macro_components.py | 3 +-- 13 files changed, 56 insertions(+), 48 deletions(-) rename libcxx/test/std/utilities/memory/allocator.traits/{ => allocator.traits.members}/allocate_at_least.pass.cpp (91%) diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index d0d057e6bbaf0e..a5c6fa22cec06c 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -304,7 +304,7 @@ Status --------------------------------------------------------------------- ``__cpp_lib_adaptor_iterator_pair_constructor`` ``202106L`` --------------------------------------------------- ----------------- - ``__cpp_lib_allocate_at_least`` ``202106L`` + ``__cpp_lib_allocate_at_least`` ``202302L`` --------------------------------------------------- ----------------- ``__cpp_lib_associative_heterogeneous_erasure`` *unimplemented* --------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index e96abc72c1648b..db731de2e43996 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -37,7 +37,9 @@ What's New in Libc++ 19.0.0? Implemented Papers ------------------ + - P2637R3 - Member ``visit`` +- P2652R2 - Disallow User Specialization of ``allocator_traits`` Improvements and New Features diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index ebab3ef735b617..eb415ed8c031fa 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -115,7 +115,7 @@ "`P2679R2 `__","LWG", "Fixing ``std::start_lifetime_as`` for arrays","February 2023","","","" "`P2674R1 `__","LWG", "A trait for implicit lifetime types","February 2023","","","" "`P2655R3 `__","LWG", "``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","February 2023","","","" -"`P2652R2 `__","LWG", "Disallow User Specialization of ``allocator_traits``","February 2023","","","" +"`P2652R2 `__","LWG", "Disallow User Specialization of ``allocator_traits``","February 2023","|Complete|","19.0","" "`P2787R1 `__","LWG", "``pmr::generator`` - Promise Types are not Values","February 2023","","","" "`P2614R2 `__","LWG", "Deprecate ``numeric_limits::has_denorm``","February 2023","|Complete|","18.0","" "`P2588R3 `__","LWG", "``barrier``’s phase completion guarantees","February 2023","","","" diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index b69b0948325412..58e995809777c1 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -2,7 +2,7 @@ "`2994 `__","Needless UB for ``basic_string`` and ``basic_string_view``","Varna June 2023","|Complete|","5.0","" "`3884 `__","``flat_foo`` is missing allocator-extended copy/move constructors","Varna June 2023","","","|flat_containers|" "`3885 `__","``op`` should be in [zombie.names]","Varna June 2023","|Nothing To Do|","","" -"`3887 `__","Version macro for ``allocate_at_least``","Varna June 2023","","","" +"`3887 `__","Version macro for ``allocate_at_least``","Varna June 2023","|Complete|","19.0","" "`3893 `__","LWG 3661 broke ``atomic> a; a = nullptr;``","Varna June 2023","","","" "`3894 `__","``generator::promise_type::yield_value(ranges::elements_of)`` should not be ``noexcept``","Varna June 2023","","","" "`3903 `__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0","" diff --git a/libcxx/include/__memory/allocate_at_least.h b/libcxx/include/__memory/allocate_at_least.h index 05cbdee828839a..b2e5dd3ff98a03 100644 --- a/libcxx/include/__memory/allocate_at_least.h +++ b/libcxx/include/__memory/allocate_at_least.h @@ -20,28 +20,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 23 -template -struct allocation_result { - _Pointer ptr; - size_t count; -}; -_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result); - -template -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result::pointer> -allocate_at_least(_Alloc& __alloc, size_t __n) { - if constexpr (requires { __alloc.allocate_at_least(__n); }) { - return __alloc.allocate_at_least(__n); - } else { - return {__alloc.allocate(__n), __n}; - } -} template [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __allocate_at_least(_Alloc& __alloc, size_t __n) { - return std::allocate_at_least(__alloc, __n); + return std::allocator_traits<_Alloc>::allocate_at_least(__alloc, __n); } + #else + template struct __allocation_result { _Pointer ptr; diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h index c4482872ea810b..3c7fc863b77bcc 100644 --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -22,6 +22,7 @@ #include <__type_traits/void_t.h> #include <__utility/declval.h> #include <__utility/forward.h> +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -231,6 +232,17 @@ struct __has_select_on_container_copy_construction< _LIBCPP_SUPPRESS_DEPRECATED_POP +#if _LIBCPP_STD_VER >= 23 + +template +struct allocation_result { + _Pointer ptr; + _SizeType count; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result); + +#endif // _LIBCPP_STD_VER + template struct _LIBCPP_TEMPLATE_VIS allocator_traits { using allocator_type = _Alloc; @@ -284,6 +296,18 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits { return __a.allocate(__n); } +#if _LIBCPP_STD_VER >= 23 + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr allocation_result + allocate_at_least(_Ap& __alloc, size_type __n) { + if constexpr (requires { __alloc.allocate_at_least(__n); }) { + return __alloc.allocate_at_least(__n); + } else { + return {__alloc.allocate(__n), __n}; + } + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT { __a.deallocate(__p, __n); diff --git a/libcxx/include/memory b/libcxx/include/memory index 19c11ee9498728..0ada7cdfa20690 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -88,6 +88,9 @@ struct allocator_traits static pointer allocate(allocator_type& a, size_type n); // constexpr and [[nodiscard]] in C++20 static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); // constexpr and [[nodiscard]] in C++20 + [[nodiscard]] static constexpr allocation_result + allocate_at_least(Alloc& a, size_type n); // Since C++23 + static void deallocate(allocator_type& a, pointer p, size_type n) noexcept; // constexpr in C++20 template @@ -100,15 +103,11 @@ struct allocator_traits static allocator_type select_on_container_copy_construction(const allocator_type& a); // constexpr in C++20 }; -template +template struct allocation_result { Pointer ptr; - size_t count; -}; // since C++23 - -template -[[nodiscard]] constexpr allocation_result::pointer> - allocate_at_least(Allocator& a, size_t n); // since C++23 + SizeType count; +}; // Since C++23 template <> class allocator // removed in C++20 diff --git a/libcxx/include/version b/libcxx/include/version index 9e26da8c1b2425..e4dbb7bdd5fc2c 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -16,7 +16,7 @@ Macro name Value Headers __cpp_lib_adaptor_iterator_pair_constructor 202106L __cpp_lib_addressof_constexpr 201603L -__cpp_lib_allocate_at_least 202106L +__cpp_lib_allocate_at_least 202302L __cpp_lib_allocator_traits_is_always_equal 201411L @@ -433,7 +433,7 @@ __cpp_lib_within_lifetime 202306L #if _LIBCPP_STD_VER >= 23 # define __cpp_lib_adaptor_iterator_pair_constructor 202106L -# define __cpp_lib_allocate_at_least 202106L +# define __cpp_lib_allocate_at_least 202302L // # define __cpp_lib_associative_heterogeneous_erasure 202110L // # define __cpp_lib_bind_back 202202L # define __cpp_lib_byteswap 202110L diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc index ef89845457fbb9..56c621c0cf17fb 100644 --- a/libcxx/modules/std/memory.inc +++ b/libcxx/modules/std/memory.inc @@ -43,8 +43,6 @@ export namespace std { #if _LIBCPP_STD_VER >= 23 using std::allocation_result; - - using std::allocate_at_least; #endif // [default.allocator], the default allocator diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp index b1f6c76d847398..45d9271faa5783 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp @@ -17,7 +17,7 @@ /* Constant Value __cpp_lib_addressof_constexpr 201603L [C++17] - __cpp_lib_allocate_at_least 202106L [C++23] + __cpp_lib_allocate_at_least 202302L [C++23] __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] __cpp_lib_assume_aligned 201811L [C++20] __cpp_lib_atomic_value_initialization 201911L [C++20] @@ -432,8 +432,8 @@ # ifndef __cpp_lib_allocate_at_least # error "__cpp_lib_allocate_at_least should be defined in c++23" # endif -# if __cpp_lib_allocate_at_least != 202106L -# error "__cpp_lib_allocate_at_least should have the value 202106L in c++23" +# if __cpp_lib_allocate_at_least != 202302L +# error "__cpp_lib_allocate_at_least should have the value 202302L in c++23" # endif # ifndef __cpp_lib_allocator_traits_is_always_equal @@ -569,8 +569,8 @@ # ifndef __cpp_lib_allocate_at_least # error "__cpp_lib_allocate_at_least should be defined in c++26" # endif -# if __cpp_lib_allocate_at_least != 202106L -# error "__cpp_lib_allocate_at_least should have the value 202106L in c++26" +# if __cpp_lib_allocate_at_least != 202302L +# error "__cpp_lib_allocate_at_least should have the value 202302L in c++26" # endif # ifndef __cpp_lib_allocator_traits_is_always_equal 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 c319940fe6e49c..29f0ba89330bb9 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 @@ -18,7 +18,7 @@ /* Constant Value __cpp_lib_adaptor_iterator_pair_constructor 202106L [C++23] __cpp_lib_addressof_constexpr 201603L [C++17] - __cpp_lib_allocate_at_least 202106L [C++23] + __cpp_lib_allocate_at_least 202302L [C++23] __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] __cpp_lib_any 201606L [C++17] __cpp_lib_apply 201603L [C++17] @@ -4279,8 +4279,8 @@ # ifndef __cpp_lib_allocate_at_least # error "__cpp_lib_allocate_at_least should be defined in c++23" # endif -# if __cpp_lib_allocate_at_least != 202106L -# error "__cpp_lib_allocate_at_least should have the value 202106L in c++23" +# if __cpp_lib_allocate_at_least != 202302L +# error "__cpp_lib_allocate_at_least should have the value 202302L in c++23" # endif # ifndef __cpp_lib_allocator_traits_is_always_equal @@ -5846,8 +5846,8 @@ # ifndef __cpp_lib_allocate_at_least # error "__cpp_lib_allocate_at_least should be defined in c++26" # endif -# if __cpp_lib_allocate_at_least != 202106L -# error "__cpp_lib_allocate_at_least should have the value 202106L in c++26" +# if __cpp_lib_allocate_at_least != 202302L +# error "__cpp_lib_allocate_at_least should have the value 202302L in c++26" # endif # ifndef __cpp_lib_allocator_traits_is_always_equal diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_at_least.pass.cpp similarity index 91% rename from libcxx/test/std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp rename to libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_at_least.pass.cpp index ad9a2381cbfa19..88ae44c6275845 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_at_least.pass.cpp @@ -39,22 +39,22 @@ struct has_allocate_at_least { constexpr T* allocate(std::size_t) { return &t1; } constexpr void deallocate(T*, std::size_t) {} - constexpr std::allocation_result allocate_at_least(std::size_t) { - return {&t2, 2}; - } + constexpr std::allocation_result allocate_at_least(std::size_t) { return {&t2, 2}; } }; constexpr bool test() { { // check that std::allocate_at_least forwards to allocator::allocate if no allocate_at_least exists no_allocate_at_least alloc; - std::same_as> decltype(auto) ret = std::allocate_at_least(alloc, 1); + std::same_as> decltype(auto) ret = + std::allocator_traits::allocate_at_least(alloc, 1); assert(ret.count == 1); assert(ret.ptr == &alloc.t); } { // check that std::allocate_at_least forwards to allocator::allocate_at_least if allocate_at_least exists has_allocate_at_least alloc; - std::same_as> decltype(auto) ret = std::allocate_at_least(alloc, 1); + std::same_as> decltype(auto) ret = + std::allocator_traits::allocate_at_least(alloc, 1); assert(ret.count == 2); assert(ret.ptr == &alloc.t2); } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 065b70620cd170..6078e811c8e1ee 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -88,9 +88,8 @@ def add_version_header(tc): { "name": "__cpp_lib_allocate_at_least", "values": { - "c++23": 202106, # Note LWG3887 Version macro for allocate_at_least - # "c++26": 202302, # P2652R2 Disallow User Specialization of allocator_traits + "c++23": 202302, # P2652R2 Disallow User Specialization of allocator_traits }, "headers": ["memory"], },