diff --git a/stl/inc/xmemory b/stl/inc/xmemory index c809f772e96..aff609d3481 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -460,6 +460,15 @@ template struct _Is_default_allocator, void_t::_From_primary>> : is_same::_From_primary, allocator<_Ty>>::type {}; +#if _HAS_CXX23 +template +inline constexpr bool _Has_member_allocate_at_least = false; + +template +inline constexpr bool _Has_member_allocate_at_least<_Alloc, _SizeTy, + void_t().allocate_at_least(_STD declval()))>> = true; +#endif // _HAS_CXX23 + template struct _Has_no_allocator_construct : true_type {}; @@ -511,6 +520,14 @@ template struct _Has_select_on_container_copy_construction<_Alloc, void_t().select_on_container_copy_construction())>> : true_type {}; +#if _HAS_CXX23 +_EXPORT_STD template +struct allocation_result { + _Ptr ptr; + _SizeTy count; +}; +#endif // _HAS_CXX23 + _EXPORT_STD template struct allocator_traits; @@ -553,6 +570,17 @@ struct _Normal_allocator_traits { // defines traits for allocators } } +#if _HAS_CXX23 + _NODISCARD_RAW_PTR_ALLOC static constexpr allocation_result allocate_at_least( + _Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { + if constexpr (_Has_member_allocate_at_least<_Alloc, size_type>) { + return _Al.allocate_at_least(_Count); + } else { + return {_Al.allocate(_Count), _Count}; + } + } +#endif // _HAS_CXX23 + static _CONSTEXPR20 void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) { _Al.deallocate(_Ptr, _Count); } @@ -653,6 +681,13 @@ struct _Default_allocator_traits { // traits for std::allocator } } +#if _HAS_CXX23 + _NODISCARD_RAW_PTR_ALLOC static constexpr allocation_result allocate_at_least( + _Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { + return {_Al.allocate(_Count), _Count}; + } +#endif // _HAS_CXX23 + static _CONSTEXPR20 void deallocate(_Alloc& _Al, const pointer _Ptr, const size_type _Count) { // no overflow check on the following multiply; we assume _Allocate did that check #if _HAS_CXX20 // TRANSITION, GH-1532 @@ -747,29 +782,6 @@ struct _Simple_types { // wraps types from allocators with simple addressing for using const_pointer = const value_type*; }; -#if _HAS_CXX23 -_EXPORT_STD template -struct allocation_result { - _Ptr ptr; - size_t count; -}; - -#ifdef __cpp_lib_concepts -template -concept _Has_member_allocate_at_least = requires(_Alloc _Al, size_t _Count) { _Al.allocate_at_least(_Count); }; - -_EXPORT_STD template -_NODISCARD constexpr allocation_result::pointer> allocate_at_least( - _Alloc& _Al, const size_t _Count) { - if constexpr (_Has_member_allocate_at_least<_Alloc>) { - return _Al.allocate_at_least(_Count); - } else { - return {_Al.allocate(_Count), _Count}; - } -} -#endif // __cpp_lib_concepts -#endif // _HAS_CXX23 - // The number of user bytes a single byte of ASAN shadow memory can track. _INLINE_VAR constexpr size_t _Asan_granularity = 8; _INLINE_VAR constexpr size_t _Asan_granularity_mask = _Asan_granularity - 1; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 0b6cdf1a024..4064264bf12 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -354,6 +354,7 @@ // P2499R0 string_view Range Constructor Should Be explicit // P2505R5 Monadic Functions For expected // P2549R1 unexpected::error() +// P2652R2 Disallowing User Specialization Of allocator_traits // _HAS_CXX23 and _SILENCE_ALL_CXX23_DEPRECATION_WARNINGS control: // P1413R3 Deprecate aligned_storage And aligned_union diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index ee34f04da44..88a05cc2ad7 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -141,6 +141,9 @@ std/ranges/range.access/rbegin.pass.cpp FAIL std/ranges/range.access/rend.pass.cpp FAIL std/ranges/range.access/size.pass.cpp FAIL +# libc++ doesn't implement P2652R2 "Disallowing User Specialization Of allocator_traits" +std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp FAIL + # libc++ doesn't implement P2770R0 "Stashing stashing iterators for proper flattening" std/ranges/range.adaptors/range.join.view/end.pass.cpp FAIL std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp FAIL diff --git a/tests/std/tests/P0401R6_allocate_at_least/env.lst b/tests/std/tests/P0401R6_allocate_at_least/env.lst index 18e2d7c71ec..642f530ffad 100644 --- a/tests/std/tests/P0401R6_allocate_at_least/env.lst +++ b/tests/std/tests/P0401R6_allocate_at_least/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0401R6_allocate_at_least/test.cpp b/tests/std/tests/P0401R6_allocate_at_least/test.cpp index e3f4e1e5756..12c1cd395c0 100644 --- a/tests/std/tests/P0401R6_allocate_at_least/test.cpp +++ b/tests/std/tests/P0401R6_allocate_at_least/test.cpp @@ -3,7 +3,10 @@ #include #include +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 #include +#endif // __cpp_lib_concepts +#include #include #include #include @@ -45,11 +48,42 @@ struct strict_allocator { } }; +struct small_allocator { + using value_type = int; + using size_type = uint32_t; + + [[nodiscard]] constexpr int* allocate(const size_type count) { + return allocator{}.allocate(count); + } + + constexpr void deallocate(int* ptr, const size_type count) { + allocator{}.deallocate(ptr, count); + } +}; + +struct huge_allocator { + using value_type = int; + using size_type = uint64_t; + + [[nodiscard]] constexpr int* allocate(const size_type count) { + return allocator{}.allocate(static_cast(count)); + } + + constexpr void deallocate(int* ptr, const size_type count) { + allocator{}.deallocate(ptr, static_cast(count)); + } +}; + constexpr bool test() { { allocator al; +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 same_as> auto result = al.allocate_at_least(5); +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + auto result = al.allocate_at_least(5); + static_assert(is_same_v>); +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ assert(result.ptr); assert(result.count >= 5); al.deallocate(result.ptr, 5); @@ -68,7 +102,12 @@ constexpr bool test() { { generous_allocator al; - same_as> auto result = allocate_at_least(al, 4); +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + same_as> auto result = allocator_traits::allocate_at_least(al, 4); +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + auto result = allocator_traits::allocate_at_least(al, 4); + static_assert(is_same_v>); +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ assert(result.ptr); assert(result.count == 16); al.deallocate(result.ptr, result.count); @@ -77,7 +116,42 @@ constexpr bool test() { { strict_allocator al; - same_as> auto result = allocate_at_least(al, 4); +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + same_as> auto result = allocator_traits::allocate_at_least(al, 4); +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + auto result = allocator_traits::allocate_at_least(al, 4); + static_assert(is_same_v>); +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ + assert(result.ptr); + assert(result.count == 4); + al.deallocate(result.ptr, result.count); + } + + { + small_allocator al; + +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + same_as> auto result = + allocator_traits::allocate_at_least(al, 4); +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + auto result = allocator_traits::allocate_at_least(al, 4); + static_assert(is_same_v>); +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ + assert(result.ptr); + assert(result.count == 4); + al.deallocate(result.ptr, result.count); + } + + { + huge_allocator al; + +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + same_as> auto result = + allocator_traits::allocate_at_least(al, 4); +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv + auto result = allocator_traits::allocate_at_least(al, 4); + static_assert(is_same_v>); +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ assert(result.ptr); assert(result.count == 4); al.deallocate(result.ptr, result.count); diff --git a/tests/std/tests/VSO_0000000_fancy_pointers/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_fancy_pointers/test.compile.pass.cpp index ad5250795e7..541b9a3f2fc 100644 --- a/tests/std/tests/VSO_0000000_fancy_pointers/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_fancy_pointers/test.compile.pass.cpp @@ -449,10 +449,9 @@ template class std::basic_osyncstream, fancy_alloca STATIC_ASSERT(std::is_standard_layout_v>>); STATIC_ASSERT(!std::is_trivially_copyable_v>>); -#ifdef __cpp_lib_concepts -STATIC_ASSERT(std::is_same_v&>(), std::size_t{})), +STATIC_ASSERT(std::is_same_v>::allocate_at_least( + std::declval&>(), std::size_t{})), std::allocation_result>>); -#endif // __cpp_lib_concepts #endif // _HAS_CXX23 void instantiate() {