diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -41,6 +41,7 @@ - P2417R2 - A more constexpr bitset - P2445R1 - ``std::forward_like`` - P2273R3 - Making ``std::unique_ptr`` constexpr +- P0591R4 - Utility functions to implement uses-allocator construction Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx20.rst b/libcxx/docs/Status/Cxx20.rst --- a/libcxx/docs/Status/Cxx20.rst +++ b/libcxx/docs/Status/Cxx20.rst @@ -40,6 +40,7 @@ .. note:: + .. [#note-P0591] P0591: The changes in [mem.poly.allocator.mem] are missing. .. [#note-P0600] P0600: The missing bits in P0600 are in |sect|\ [mem.res.class] and |sect|\ [mem.poly.allocator.class]. .. [#note-P0645] P0645: The paper is implemented but still marked as an incomplete feature (the feature-test macro is not set and the libary is only available when built with ``-fexperimental-library``). diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -149,7 +149,7 @@ "`3169 `__","``ranges``\ permutation generators discard useful information","Cologne","|Complete|","15.0","|ranges|" "`3183 `__","Normative permission to specialize Ranges variable templates","Cologne","|Nothing To Do|","","|ranges|" "`3184 `__","Inconsistencies in ``bind_front``\ wording","Cologne","|Complete|","13.0" -"`3185 `__","Uses-allocator construction functions missing ``constexpr``\ and ``noexcept``\ ","Cologne","","" +"`3185 `__","Uses-allocator construction functions missing ``constexpr``\ and ``noexcept``\ ","Cologne","|Complete|","16.0" "`3186 `__","``ranges``\ removal, partition, and ``partial_sort_copy``\ algorithms discard useful information","Cologne","|Complete|","15.0","|ranges|" "`3187 `__","`P0591R4 `__ reverted DR 2586 fixes to ``scoped_allocator_adaptor::construct()``\ ","Cologne","","" "`3191 `__","``std::ranges::shuffle``\ synopsis does not match algorithm definition","Cologne","|Complete|","15.0","|ranges|" @@ -243,7 +243,7 @@ "`3318 `__","Clarify whether clocks can represent time before their epoch","Prague","","","|chrono|" "`3319 `__","Properly reference specification of IANA time zone database","Prague","","","|chrono|" "`3320 `__","``span::cbegin/cend``\ methods produce different results than ``std::[ranges::]cbegin/cend``\ ","Prague","|Complete|","" -"`3321 `__","``uninitialized_construct_using_allocator``\ should use ``construct_at``\ ","Prague","","" +"`3321 `__","``uninitialized_construct_using_allocator``\ should use ``construct_at``\ ","Prague","|Complete|","16.0" "`3323 `__","``*has-tuple-element*``\ helper concept needs ``convertible_to``\ ","Prague","","","|ranges|" "`3324 `__","Special-case ``std::strong/weak/partial_order``\ for pointers","Prague","|Complete|","14.0","|spaceship|" "`3325 `__","Constrain return type of transformation function for ``transform_view``\ ","Prague","|Complete|","15.0","|ranges|" diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -55,8 +55,8 @@ "`P0357R3 `__","LWG","reference_wrapper for incomplete types","San Diego","|Complete|","8.0" "`P0482R6 `__","CWG","char8_t: A type for UTF-8 characters and strings","San Diego","|Partial| [#note-P0482]_","16.0" "`P0487R1 `__","LWG","Fixing ``operator>>(basic_istream&, CharT*)``\ (LWG 2499)","San Diego","|Complete|","8.0" -"`P0591R4 `__","LWG","Utility functions to implement uses-allocator construction","San Diego","* *","" -"`P0595R2 `__","CWG","P0595R2 std::is_constant_evaluated()","San Diego","|Complete|","9.0" +"`P0591R4 `__","LWG","Utility functions to implement uses-allocator construction","San Diego","|Partial| [#note-P0591]_","" +"`P0595R2 `__","CWG","std::is_constant_evaluated()","San Diego","|Complete|","9.0" "`P0602R4 `__","LWG","variant and optional should propagate copy/move triviality","San Diego","|Complete|","8.0" "`P0608R3 `__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0" "`P0655R1 `__","LWG","visit: Explicit Return Type for visit","San Diego","|Complete|","12.0" diff --git a/libcxx/docs/Status/ZipProjects.csv b/libcxx/docs/Status/ZipProjects.csv --- a/libcxx/docs/Status/ZipProjects.csv +++ b/libcxx/docs/Status/ZipProjects.csv @@ -4,7 +4,7 @@ | `[utility.syn] `_, "[pair] basic_common_reference, common_type", None, Nikolas Klauser, |Complete| | `[pairs.pair] `_, "`[pair] constructor, assignment and swap overloads `_", None, Hui Xie, |Complete| "| `[memory.syn] `_ -| `[allocator.uses.construction] `_", "[pair] uses_allocator_construction_args overloads", None, Unassigned, |Not Started| +| `[allocator.uses.construction] `_", "[pair] uses_allocator_construction_args overloads", None, Nikolas Klauser, |Complete| | `[vector.bool] `_, "[vector::reference] add const operator= overload", None, Hui Xie, |Not Started| | `[iterator.concept.winc] `_, "Update weakly_comparable", None, Hui Xie, |Not Started| | `[range.zip] `_, "`zip_view `_", "| `zip_view::iterator` diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -412,6 +412,7 @@ __memory/uninitialized_algorithms.h __memory/unique_ptr.h __memory/uses_allocator.h + __memory/uses_allocator_construction.h __memory/voidify.h __mutex_base __node_handle diff --git a/libcxx/include/__memory/uses_allocator_construction.h b/libcxx/include/__memory/uses_allocator_construction.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/uses_allocator_construction.h @@ -0,0 +1,219 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H +#define _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H + +#include <__config> +#include <__memory/construct_at.h> +#include <__memory/uses_allocator.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_same.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +inline constexpr bool __is_std_pair = false; + +template +inline constexpr bool __is_std_pair> = true; + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept { + if constexpr (!uses_allocator_v<_Type, _Alloc> && is_constructible_v<_Type, _Args...>) { + return std::forward_as_tuple(std::forward<_Args>(__args)...); + } else if constexpr (uses_allocator_v<_Type, _Alloc> && + is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) { + return tuple(allocator_arg, __alloc, std::forward<_Args>(__args)...); + } else if constexpr (uses_allocator_v<_Type, _Alloc> && is_constructible_v<_Type, _Args..., const _Alloc&>) { + return std::forward_as_tuple(std::forward<_Args>(__args)..., __alloc); + } else { + static_assert( + sizeof(_Type) + 1 == 0, "If uses_allocator_v is true, the type has to be allocator-constructible"); + } +} + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args( + const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept { + return std::make_tuple( + piecewise_construct, + std::apply( + [&__alloc](auto&&... __args1) { + return std::__uses_allocator_construction_args( + __alloc, std::forward(__args1)...); + }, + std::forward<_Tuple1>(__x)), + std::apply( + [&__alloc](auto&&... __args2) { + return std::__uses_allocator_construction_args( + __alloc, std::forward(__args2)...); + }, + std::forward<_Tuple2>(__y))); +} + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc) noexcept { + return std::__uses_allocator_construction_args<_Pair>(__alloc, piecewise_construct, tuple<>{}, tuple<>{}); +} + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept { + return std::__uses_allocator_construction_args<_Pair>( + __alloc, + piecewise_construct, + std::forward_as_tuple(std::forward<_Up>(__u)), + std::forward_as_tuple(std::forward<_Vp>(__v))); +} + +# if _LIBCPP_STD_VER > 20 +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair) noexcept { + return std::__uses_allocator_construction_args<_Pair>( + __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second)); +} +# endif + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept { + return std::__uses_allocator_construction_args<_Pair>( + __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second)); +} + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept { + return std::__uses_allocator_construction_args<_Pair>( + __alloc, + piecewise_construct, + std::forward_as_tuple(std::get<0>(std::move(__pair))), + std::forward_as_tuple(std::get<1>(std::move(__pair)))); +} + +# if _LIBCPP_STD_VER > 20 +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&& __pair) noexcept { + return std::__uses_allocator_construction_args<_Pair>( + __alloc, + piecewise_construct, + std::forward_as_tuple(std::get<0>(std::move(__pair))), + std::forward_as_tuple(std::get<1>(std::move(__pair)))); +} +# endif + +namespace __uses_allocator_detail { + +template +void __fun(const pair<_Ap, _Bp>&); + +template +decltype(__uses_allocator_detail::__fun(std::declval<_Tp>()), true_type()) __convertible_to_const_pair_ref_impl(int); + +template +false_type __convertible_to_const_pair_ref_impl(...); + +template +inline constexpr bool __convertible_to_const_pair_ref = + decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl<_Tp>(0))::value; + +} // namespace __uses_allocator_detail + +template < + class _Pair, + class _Alloc, + class _Type, + __enable_if_t<__is_std_pair<_Pair> && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept; + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args); + +template && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int>> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept { + struct __pair_constructor { + using _PairMutable = remove_cv_t<_Pair>; + + _LIBCPP_HIDE_FROM_ABI constexpr auto __do_construct(const _PairMutable& __pair) const { + return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto __do_construct(_PairMutable&& __pair) const { + return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair)); + } + + const _Alloc& __alloc_; + _Type& __value_; + + _LIBCPP_HIDE_FROM_ABI constexpr operator _PairMutable() const { + return __do_construct(std::forward<_Type>(this->__value_)); + } + }; + + return std::make_tuple(__pair_constructor{__alloc, __value}); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) { + return std::make_from_tuple<_Type>( + std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...)); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Type* +__uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) { + return std::apply( + [&__ptr](auto&&... __xs) { return std::__construct_at(__ptr, std::forward(__xs)...); }, + std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...)); +} + +#endif // _LIBCPP_STD_VER >= 17 + +#if _LIBCPP_STD_VER >= 20 + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept + -> decltype(std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...)) { + return /*--*/ std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) + -> decltype(std::__make_obj_using_allocator<_Type>(__alloc, std::forward<_Args>(__args)...)) { + return /*--*/ std::__make_obj_using_allocator<_Type>(__alloc, std::forward<_Args>(__args)...); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto +uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) + -> decltype(std::__uninitialized_construct_using_allocator(__ptr, __alloc, std::forward<_Args>(__args)...)) { + return /*--*/ std::__uninitialized_construct_using_allocator(__ptr, __alloc, std::forward<_Args>(__args)...); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -883,6 +883,7 @@ #include <__memory/uninitialized_algorithms.h> #include <__memory/unique_ptr.h> #include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> #include // standard-mandated includes diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -878,6 +878,7 @@ module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" } module unique_ptr { private header "__memory/unique_ptr.h" } module uses_allocator { private header "__memory/uses_allocator.h" } + module uses_allocator_construction { private header "__memory/uses_allocator_construction.h" } module voidify { private header "__memory/voidify.h" } } } diff --git a/libcxx/include/scoped_allocator b/libcxx/include/scoped_allocator --- a/libcxx/include/scoped_allocator +++ b/libcxx/include/scoped_allocator @@ -112,6 +112,7 @@ #include <__assert> // all public C++ headers provide the assertion handler #include <__config> #include <__memory/allocator_traits.h> +#include <__memory/uses_allocator_construction.h> #include <__type_traits/common_type.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> @@ -523,6 +524,18 @@ size_type max_size() const {return allocator_traits::max_size(outer_allocator());} +#if _LIBCPP_STD_VER >= 20 + template + _LIBCPP_HIDE_FROM_ABI void construct(_Type* __ptr, _Args&&... __args) { + using _OM = __outermost; + std::apply( + [__ptr, this](auto&&... __newargs) { + allocator_traits::construct( + _OM()(outer_allocator()), __ptr, std::forward(__newargs)...); + }, + std::uses_allocator_construction_args<_Type>(inner_allocator(), std::forward<_Args>(__args)...)); + } +#else template _LIBCPP_INLINE_VISIBILITY void construct(_Tp* __p, _Args&& ...__args) @@ -577,6 +590,7 @@ _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__x.first)), _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__x.second))); } +#endif template _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -443,6 +443,7 @@ #include <__memory/uninitialized_algorithms.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uninitialized_algorithms.h'}} #include <__memory/unique_ptr.h> // expected-error@*:* {{use of private header from outside its module: '__memory/unique_ptr.h'}} #include <__memory/uses_allocator.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uses_allocator.h'}} +#include <__memory/uses_allocator_construction.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uses_allocator_construction.h'}} #include <__memory/voidify.h> // expected-error@*:* {{use of private header from outside its module: '__memory/voidify.h'}} #include <__mutex_base> // expected-error@*:* {{use of private header from outside its module: '__mutex_base'}} #include <__node_handle> // expected-error@*:* {{use of private header from outside its module: '__node_handle'}} diff --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv --- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv @@ -478,6 +478,7 @@ memory limits memory new memory stdexcept +memory tuple memory type_traits memory typeinfo memory version diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct.pass.cpp @@ -115,10 +115,10 @@ { static bool constructed; - typedef std::allocator allocator_type; + typedef std::scoped_allocator_adaptor> allocator_type; G(std::allocator_arg_t, allocator_type&&) { assert(false); } - G(allocator_type&) { constructed = true; } + G(const allocator_type&) { constructed = true; } }; bool G::constructed = false; @@ -202,7 +202,7 @@ // Test that is_constructible uses an lvalue ref so the correct constructor // is picked. { - std::scoped_allocator_adaptor sa; + G::allocator_type sa; G* ptr = sa.allocate(1); sa.construct(ptr); assert(G::constructed); diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp @@ -46,10 +46,17 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, CA)); assert(checkConstruct<>(ptr->second, UA_AllocLast, CA)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); @@ -69,10 +76,17 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, CA)); assert(checkConstruct<>(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple<>&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple<>&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -102,10 +116,17 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, I)); assert(checkConstruct<>(ptr->second, UA_AllocLast)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -129,10 +150,17 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, I)); assert(checkConstruct<>(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple<>&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple<>&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp @@ -50,10 +50,17 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); @@ -77,10 +84,17 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -114,10 +128,17 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -145,10 +166,17 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp @@ -51,10 +51,17 @@ std::forward_as_tuple(std::move(y))); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); @@ -78,10 +85,17 @@ std::forward_as_tuple(y)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -115,10 +129,17 @@ std::forward_as_tuple(std::move(y))); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -146,10 +167,17 @@ std::forward_as_tuple(std::move(y))); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp @@ -50,10 +50,17 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); @@ -77,10 +84,17 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -114,10 +128,17 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -145,10 +166,17 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp @@ -48,10 +48,17 @@ A.construct(ptr, x, std::move(y)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); @@ -73,10 +80,17 @@ A.construct(ptr, std::move(x), y); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((P.checkConstruct&&, + std::tuple&& + >(CA, ptr))); +#else assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -108,10 +122,17 @@ A.construct(ptr, x, std::move(y)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } @@ -137,10 +158,17 @@ A.construct(ptr, std::move(x), std::move(y)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct&&, + std::tuple&& + >(O, ptr))); +#else assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); +#endif A.destroy(ptr); std::free(ptr); } diff --git a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp --- a/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp +++ b/libcxx/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp @@ -84,8 +84,13 @@ int const& cx = x; A.construct(ptr, x, cx, std::move(x)); assert((checkConstruct(*ptr, UA_AllocArg, I))); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct(O, ptr))); +#else assert((POuter.checkConstruct(O, ptr))); +#endif A.destroy(ptr); ::operator delete((void*)ptr); } @@ -117,9 +122,15 @@ int const& cx = x; A.construct(ptr, x, cx, std::move(x)); assert((checkConstruct(*ptr, UA_AllocLast, I))); +#if TEST_STD_VER >= 20 + assert((POuter.checkConstruct< + int&, int const&, int&&, + const SA::inner_allocator_type&>(O, ptr))); +#else assert((POuter.checkConstruct< int&, int const&, int&&, SA::inner_allocator_type&>(O, ptr))); +#endif A.destroy(ptr); ::operator delete((void*)ptr); } diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/common.h b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/common.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/common.h @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "test_allocator.h" + +using Alloc = test_allocator; + +enum class RefType { + LValue, + ConstLValue, + RValue, + ConstRValue, +}; + +struct UsesAllocArgT { + using allocator_type = Alloc; + + bool allocator_constructed_ = false; + Alloc a_; + const Alloc& alloc_ = a_; + const int* val_ptr_; + RefType ref_type_; + + constexpr UsesAllocArgT() = default; + constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc) : allocator_constructed_(true), alloc_(alloc) {} + constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, int& val) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::LValue) {} + constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, const int& val) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstLValue) {} + constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, int&& val) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::RValue) {} + constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, const int&& val) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstRValue) {} +}; + +struct UsesAllocLast { + using allocator_type = Alloc; + + bool allocator_constructed_ = false; + Alloc a_; + const Alloc& alloc_ = a_; + const int* val_ptr_; + RefType ref_type_; + + constexpr UsesAllocLast() = default; + constexpr UsesAllocLast(const Alloc& alloc) : allocator_constructed_(true), alloc_(alloc) {} + constexpr UsesAllocLast(int& val, const Alloc& alloc) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::LValue) {} + constexpr UsesAllocLast(const int& val, const Alloc& alloc) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstLValue) {} + constexpr UsesAllocLast(int&& val, const Alloc& alloc) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::RValue) {} + constexpr UsesAllocLast(const int&& val, const Alloc& alloc) + : allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstRValue) {} +}; + +struct NotAllocatorAware { + bool allocator_constructed_ = false; + + constexpr NotAllocatorAware() = default; + constexpr NotAllocatorAware(const Alloc&) : allocator_constructed_(true) {} + constexpr NotAllocatorAware(const Alloc&, int) : allocator_constructed_(true) {} +}; + +struct ConvertibleToPair { + constexpr operator std::pair() const { return {1, 2}; } +}; diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/make_obj_using_allocator.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/make_obj_using_allocator.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/make_obj_using_allocator.pass.cpp @@ -0,0 +1,139 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// template +// constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include + +#include "common.h" +#include "test_allocator.h" + +constexpr bool test() { + Alloc a(12); + { + std::same_as auto ret = std::make_obj_using_allocator(a); + assert(ret.allocator_constructed_); + assert(&ret.alloc_ == &a); + } + { + std::same_as auto ret = std::make_obj_using_allocator(a); + assert(ret.allocator_constructed_); + assert(&ret.alloc_ == &a); + } + { + std::same_as auto ret = std::make_obj_using_allocator(a); + assert(!ret.allocator_constructed_); + } + { + std::same_as> auto ret = + std::make_obj_using_allocator>( + a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{}); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + } + { + std::same_as> auto ret = + std::make_obj_using_allocator>(a); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + } + { + std::same_as> auto ret = + std::make_obj_using_allocator>(a, 0, 0); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + } +#if TEST_STD_VER >= 23 + { + std::pair p{0, 0}; + + std::same_as> auto ret = + std::make_obj_using_allocator>(a, p); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.first.ref_type_ == RefType::LValue); + assert(ret.first.val_ptr_ == &p.first); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + assert(ret.second.ref_type_ == RefType::LValue); + assert(ret.second.val_ptr_ == &p.second); + } +#endif + { + std::pair p{0, 0}; + std::same_as> auto ret = + std::make_obj_using_allocator>(a, std::as_const(p)); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.first.ref_type_ == RefType::ConstLValue); + assert(ret.first.val_ptr_ == &p.first); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + assert(ret.second.ref_type_ == RefType::ConstLValue); + assert(ret.second.val_ptr_ == &p.second); + } + { + std::pair p{0, 0}; + std::same_as> auto ret = + std::make_obj_using_allocator>(a, std::move(p)); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.first.ref_type_ == RefType::RValue); + assert(ret.first.val_ptr_ == &p.first); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + assert(ret.second.ref_type_ == RefType::RValue); + assert(ret.second.val_ptr_ == &p.second); + } +#if TEST_STD_VER >= 23 + { + std::pair p{0, 0}; + std::same_as> auto ret = + std::make_obj_using_allocator>(a, std::move(std::as_const(p))); + assert(ret.first.allocator_constructed_); + assert(&ret.first.alloc_ == &a); + assert(ret.first.ref_type_ == RefType::ConstRValue); + assert(ret.first.val_ptr_ == &p.first); + assert(ret.second.allocator_constructed_); + assert(&ret.second.alloc_ == &a); + assert(ret.second.ref_type_ == RefType::ConstRValue); + assert(ret.second.val_ptr_ == &p.second); + } +#endif + { + ConvertibleToPair ctp; + std::same_as> auto ret = std::make_obj_using_allocator>(a, ctp); + assert(ret.first == 1); + assert(ret.second == 2); + } + { + ConvertibleToPair ctp; + std::same_as> auto ret = std::make_obj_using_allocator>(a, std::move(ctp)); + assert(ret.first == 1); + assert(ret.second == 2); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/tested_elsewhere.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/tested_elsewhere.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/tested_elsewhere.pass.cpp +++ /dev/null @@ -1,13 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -int main(int, char**) -{ - - return 0; -} diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uninitialized_construct_using_allocator.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uninitialized_construct_using_allocator.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uninitialized_construct_using_allocator.pass.cpp @@ -0,0 +1,185 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// template +// constexpr T uninitialized_construct_using_allocator(const Alloc& alloc, Args&&... args); + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include + +#include "common.h" +#include "test_allocator.h" + +constexpr bool test() { + Alloc a(12); + { + auto* ptr = std::allocator{}.allocate(1); + std::same_as auto ret = std::uninitialized_construct_using_allocator(ptr, a); + assert(ret == ptr); + assert(ret->allocator_constructed_); + assert(&ret->alloc_ == &a); + std::allocator{}.deallocate(ptr, 1); + } + { + auto* ptr = std::allocator{}.allocate(1); + std::same_as auto ret = std::uninitialized_construct_using_allocator(ptr, a); + assert(ret->allocator_constructed_); + assert(&ret->alloc_ == &a); + std::allocator{}.deallocate(ptr, 1); + } + { + auto* ptr = std::allocator{}.allocate(1); + std::same_as auto ret = std::uninitialized_construct_using_allocator(ptr, a); + assert(!ret->allocator_constructed_); + std::allocator{}.deallocate(ptr, 1); + } + { + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{}); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + std::allocator>{}.deallocate(ptr, 1); + } + { + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + std::allocator>{}.deallocate(ptr, 1); + } + { + int val = 0; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, val, val); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->first.ref_type_ == RefType::LValue); + assert(ret->first.val_ptr_ == &val); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + assert(ret->second.ref_type_ == RefType::LValue); + assert(ret->second.val_ptr_ == &val); + std::allocator>{}.deallocate(ptr, 1); + } + { + int val = 0; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, std::move(val), std::move(val)); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->first.ref_type_ == RefType::RValue); + assert(ret->first.val_ptr_ == &val); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + assert(ret->second.ref_type_ == RefType::RValue); + assert(ret->second.val_ptr_ == &val); + std::allocator>{}.deallocate(ptr, 1); + } +#if TEST_STD_VER >= 23 + { + std::pair p{0, 0}; + + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, p); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->first.ref_type_ == RefType::LValue); + assert(ret->first.val_ptr_ == &p.first); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + assert(ret->second.ref_type_ == RefType::LValue); + assert(ret->second.val_ptr_ == &p.second); + std::allocator>{}.deallocate(ptr, 1); + } +#endif + { + std::pair p{0, 0}; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, std::as_const(p)); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->first.ref_type_ == RefType::ConstLValue); + assert(ret->first.val_ptr_ == &p.first); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + assert(ret->second.ref_type_ == RefType::ConstLValue); + assert(ret->second.val_ptr_ == &p.second); + std::allocator>{}.deallocate(ptr, 1); + } + { + std::pair p{0, 0}; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, std::move(p)); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->first.ref_type_ == RefType::RValue); + assert(ret->first.val_ptr_ == &p.first); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + assert(ret->second.ref_type_ == RefType::RValue); + assert(ret->second.val_ptr_ == &p.second); + std::allocator>{}.deallocate(ptr, 1); + } +#if TEST_STD_VER >= 23 + { + std::pair p{0, 0}; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = + std::uninitialized_construct_using_allocator(ptr, a, std::move(std::as_const(p))); + assert(ret->first.allocator_constructed_); + assert(&ret->first.alloc_ == &a); + assert(ret->first.ref_type_ == RefType::ConstRValue); + assert(ret->first.val_ptr_ == &p.first); + assert(ret->second.allocator_constructed_); + assert(&ret->second.alloc_ == &a); + assert(ret->second.ref_type_ == RefType::ConstRValue); + assert(ret->second.val_ptr_ == &p.second); + std::allocator>{}.deallocate(ptr, 1); + } +#endif + { + ConvertibleToPair ctp; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = std::uninitialized_construct_using_allocator(ptr, a, ctp); + assert(ret == ptr); + assert(ret->first == 1); + assert(ret->second == 2); + std::allocator>{}.deallocate(ptr, 1); + } + { + ConvertibleToPair ctp; + auto* ptr = std::allocator>{}.allocate(1); + std::same_as*> auto ret = std::uninitialized_construct_using_allocator(ptr, a, std::move(ctp)); + assert(ret == ptr); + assert(ret->first == 1); + assert(ret->second == 2); + std::allocator>{}.deallocate(ptr, 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// template +// constexpr auto uses_allocator_construction_args(const Alloc& alloc, ...) noexcept; + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include + +#include "common.h" +#include "test_allocator.h" + +template +constexpr decltype(auto) test_uses_allocator_construction_args(Args&&... args) { + static_assert(noexcept(std::uses_allocator_construction_args(std::forward(args)...))); + return std::uses_allocator_construction_args(std::forward(args)...); +} + +constexpr bool test() { + Alloc a(12); + { + std::same_as> auto ret = + test_uses_allocator_construction_args(a); + assert(std::get<1>(ret).get_data() == 12); + } + { + std::same_as> auto ret = test_uses_allocator_construction_args(a); + assert(std::get<0>(ret).get_data() == 12); + } + { + [[maybe_unused]] std::same_as> auto ret = test_uses_allocator_construction_args(a); + } + { + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>( + a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{}); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<0>(std::get<2>(ret)).get_data() == 12); + } + { + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>(a); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<0>(std::get<2>(ret)).get_data() == 12); + } + { + int val = 0; + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>(a, val, val); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<1>(std::get<2>(ret)).get_data() == 12); + assert(&std::get<2>(std::get<1>(ret)) == &val); + assert(&std::get<0>(std::get<2>(ret)) == &val); + } + { + int val = 0; + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>( + a, std::move(val), std::move(val)); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<1>(std::get<2>(ret)).get_data() == 12); + assert(&std::get<2>(std::get<1>(ret)) == &val); + assert(&std::get<0>(std::get<2>(ret)) == &val); + } +#if TEST_STD_VER >= 23 + { + std::pair p{3, 4}; + + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>(a, p); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<1>(std::get<2>(ret)).get_data() == 12); + assert(std::get<2>(std::get<1>(ret)) == 3); + assert(std::get<0>(std::get<2>(ret)) == 4); + } +#endif + { + std::pair p{3, 4}; + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>(a, std::as_const(p)); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<1>(std::get<2>(ret)).get_data() == 12); + assert(std::get<2>(std::get<1>(ret)) == 3); + assert(std::get<0>(std::get<2>(ret)) == 4); + } + { + std::pair p{3, 4}; + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>(a, std::move(p)); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<1>(std::get<2>(ret)).get_data() == 12); + assert(std::get<2>(std::get<1>(ret)) == 3); + assert(std::get<0>(std::get<2>(ret)) == 4); + } +#if TEST_STD_VER >= 23 + { + std::pair p{3, 4}; + std::same_as, + std::tuple>> auto ret = + test_uses_allocator_construction_args>(a, std::move(std::as_const(p))); + assert(std::get<1>(std::get<1>(ret)).get_data() == 12); + assert(std::get<1>(std::get<2>(ret)).get_data() == 12); + assert(std::get<2>(std::get<1>(ret)) == 3); + assert(std::get<0>(std::get<2>(ret)) == 4); + } +#endif + { + ConvertibleToPair ctp {}; + auto ret = test_uses_allocator_construction_args>(a, ctp); + std::pair v = std::get<0>(ret); + assert(std::get<0>(v) == 1); + assert(std::get<1>(v) == 2); + } + { + ConvertibleToPair ctp {}; + auto ret = test_uses_allocator_construction_args>(a, std::move(ctp)); + std::pair v = std::get<0>(ret); + assert(std::get<0>(v) == 1); + assert(std::get<1>(v) == 2); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/test/support/MoveOnly.h b/libcxx/test/support/MoveOnly.h --- a/libcxx/test/support/MoveOnly.h +++ b/libcxx/test/support/MoveOnly.h @@ -23,7 +23,7 @@ MoveOnly(const MoveOnly&) = delete; MoveOnly& operator=(const MoveOnly&) = delete; - TEST_CONSTEXPR_CXX14 MoveOnly(MoveOnly&& x) + TEST_CONSTEXPR_CXX14 MoveOnly(MoveOnly&& x) TEST_NOEXCEPT : data_(x.data_) {x.data_ = 0;} TEST_CONSTEXPR_CXX14 MoveOnly& operator=(MoveOnly&& x) {data_ = x.data_; x.data_ = 0; return *this;}