diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 98b49f92bdf7a..7b5bcd69f6abd 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -151,7 +151,7 @@ "`LWG3184 `__","Inconsistencies in ``bind_front``\ wording","2019-07 (Cologne)","|Complete|","13","" "`LWG3185 `__","Uses-allocator construction functions missing ``constexpr``\ and ``noexcept``\ ","2019-07 (Cologne)","|Complete|","16","" "`LWG3186 `__","``ranges``\ removal, partition, and ``partial_sort_copy``\ algorithms discard useful information","2019-07 (Cologne)","|Complete|","15","" -"`LWG3187 `__","`P0591R4 `__ reverted DR 2586 fixes to ``scoped_allocator_adaptor::construct()``\ ","2019-07 (Cologne)","","","" +"`LWG3187 `__","`P0591R4 `__ reverted DR 2586 fixes to ``scoped_allocator_adaptor::construct()``\ ","2019-07 (Cologne)","|Complete|","22","" "`LWG3191 `__","``std::ranges::shuffle``\ synopsis does not match algorithm definition","2019-07 (Cologne)","|Complete|","15","" "`LWG3196 `__","``std::optional``\ is ill-formed is ``T``\ is an array","2019-07 (Cologne)","|Complete|","","" "`LWG3198 `__","Bad constraint on ``std::span::span()``\ ","2019-07 (Cologne)","|Complete|","","" diff --git a/libcxx/include/__memory/allocator_arg_t.h b/libcxx/include/__memory/allocator_arg_t.h index 31a73fc4557ef..a3dac879f45b6 100644 --- a/libcxx/include/__memory/allocator_arg_t.h +++ b/libcxx/include/__memory/allocator_arg_t.h @@ -14,6 +14,7 @@ #include <__memory/uses_allocator.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_constructible.h> +#include <__type_traits/remove_cv.h> #include <__type_traits/remove_cvref.h> #include <__utility/forward.h> @@ -40,34 +41,15 @@ constexpr allocator_arg_t allocator_arg = allocator_arg_t(); template struct __uses_alloc_ctor_imp { using _RawAlloc _LIBCPP_NODEBUG = __remove_cvref_t<_Alloc>; - static const bool __ua = uses_allocator<_Tp, _RawAlloc>::value; - static const bool __ic = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value; - static const int value = __ua ? 2 - __ic : 0; + static constexpr bool __ua = uses_allocator<__remove_cv_t<_Tp>, _RawAlloc>::value; + static constexpr bool __ic_head = is_constructible<_Tp, allocator_arg_t, const _RawAlloc&, _Args...>::value; + static constexpr bool __ic_tail = is_constructible<_Tp, _Args..., const _RawAlloc&>::value; + static constexpr int value = __ua ? (__ic_head ? 1 : __ic_tail ? 2 : -1) : 0; }; template struct __uses_alloc_ctor : integral_constant::value> {}; -template -inline _LIBCPP_HIDE_FROM_ABI void -__user_alloc_construct_impl(integral_constant, _Tp* __storage, const _Allocator&, _Args&&... __args) { - new (__storage) _Tp(std::forward<_Args>(__args)...); -} - -// FIXME: This should have a version which takes a non-const alloc. -template -inline _LIBCPP_HIDE_FROM_ABI void -__user_alloc_construct_impl(integral_constant, _Tp* __storage, const _Allocator& __a, _Args&&... __args) { - new (__storage) _Tp(allocator_arg, __a, std::forward<_Args>(__args)...); -} - -// FIXME: This should have a version which takes a non-const alloc. -template -inline _LIBCPP_HIDE_FROM_ABI void -__user_alloc_construct_impl(integral_constant, _Tp* __storage, const _Allocator& __a, _Args&&... __args) { - new (__storage) _Tp(std::forward<_Args>(__args)..., __a); -} - #endif // _LIBCPP_CXX03_LANG _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__memory/uses_allocator_construction.h b/libcxx/include/__memory/uses_allocator_construction.h index 6733f5cf6fc35..dd8e851e32455 100644 --- a/libcxx/include/__memory/uses_allocator_construction.h +++ b/libcxx/include/__memory/uses_allocator_construction.h @@ -16,6 +16,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/remove_cv.h> #include <__utility/declval.h> +#include <__utility/integer_sequence.h> #include <__utility/pair.h> #include <__utility/piecewise_construct.h> #include @@ -29,6 +30,43 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +// TODO: Guard this furtherly with _LIBCPP_STD_VER < 20 once P0591R4 is fully implemented. +#if !defined(_LIBCPP_CXX03_LANG) + +template +_LIBCPP_HIDE_FROM_ABI void __transform_tuple_using_allocator_impl( + integral_constant, const _Alloc&, tuple<_Args...>&&, __index_sequence<_Is...>) { + static_assert(false, "If uses_allocator_v is true, T has to be allocator-constructible"); +} + +template +_LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> __transform_tuple_using_allocator_impl( + integral_constant, const _Alloc&, tuple<_Args...>&& __t, __index_sequence<_Is...>) { + return tuple<_Args&&...>(std::move(__t)); +} + +template +_LIBCPP_HIDE_FROM_ABI tuple __transform_tuple_using_allocator_impl( + integral_constant, const _Alloc& __a, tuple<_Args...>&& __t, __index_sequence<_Is...>) { + return tuple(allocator_arg, __a, std::get<_Is>(std::move(__t))...); +} + +template +_LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., const _Alloc&> __transform_tuple_using_allocator_impl( + integral_constant, const _Alloc& __a, tuple<_Args...>&& __t, __index_sequence<_Is...>) { + return tuple<_Args&&..., const _Alloc&>(std::get<_Is>(std::move(__t))..., __a); +} + +template +_LIBCPP_HIDE_FROM_ABI auto __transform_tuple_using_allocator(const _Alloc& __a, tuple<_Args...>&& __t) + -> decltype(std::__transform_tuple_using_allocator_impl( + __uses_alloc_ctor<_Tp, _Alloc, _Args...>{}, __a, std::move(__t), __make_index_sequence{})) { + return std::__transform_tuple_using_allocator_impl( + __uses_alloc_ctor<_Tp, _Alloc, _Args...>{}, __a, std::move(__t), __make_index_sequence{}); +} + +#endif // !defined(_LIBCPP_CXX03_LANG) + #if _LIBCPP_STD_VER >= 17 template diff --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h index 9a351199b5b16..ec38a3469675b 100644 --- a/libcxx/include/__memory_resource/polymorphic_allocator.h +++ b/libcxx/include/__memory_resource/polymorphic_allocator.h @@ -14,9 +14,15 @@ #include <__cstddef/byte.h> #include <__cstddef/max_align_t.h> #include <__fwd/pair.h> +#include <__memory/allocator_arg_t.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> #include <__memory_resource/memory_resource.h> #include <__new/exceptions.h> #include <__new/placement_new_delete.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/remove_cv.h> +#include <__utility/as_const.h> #include <__utility/exception_guard.h> #include <__utility/piecewise_construct.h> #include @@ -122,11 +128,18 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator { template _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) { - std::__user_alloc_construct_impl( - typename __uses_alloc_ctor<_Tp, polymorphic_allocator&, _Ts...>::type(), - __p, - *this, - std::forward<_Ts>(__args)...); + if constexpr (!uses_allocator_v, polymorphic_allocator>) { + static_assert(is_constructible_v<_Tp, _Ts...>, + "If uses_allocator_v is false, T has to be constructible from arguments"); + ::new ((void*)__p) _Tp(std::forward<_Ts>(__args)...); + } else if constexpr (is_constructible_v<_Tp, allocator_arg_t, const polymorphic_allocator&, _Ts...>) { + ::new ((void*)__p) _Tp(allocator_arg, std::as_const(*this), std::forward<_Ts>(__args)...); + } else if constexpr (is_constructible_v<_Tp, _Ts..., const polymorphic_allocator&>) { + ::new ((void*)__p) _Tp(std::forward<_Ts>(__args)..., std::as_const(*this)); + } else { + static_assert( + false, "If uses_allocator_v is true, T has to be allocator-constructible"); + } } template @@ -134,12 +147,8 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator { construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) { ::new ((void*)__p) pair<_T1, _T2>( piecewise_construct, - __transform_tuple(typename __uses_alloc_ctor< _T1, polymorphic_allocator&, _Args1... >::type(), - std::move(__x), - make_index_sequence()), - __transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(), - std::move(__y), - make_index_sequence())); + std::__transform_tuple_using_allocator<_T1>(*this, std::move(__x)), + std::__transform_tuple_using_allocator<_T2>(*this, std::move(__y))); } template @@ -193,26 +202,6 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator { # endif private: - template - _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> - __transform_tuple(integral_constant, tuple<_Args...>&& __t, index_sequence<_Is...>) { - return std::forward_as_tuple(std::get<_Is>(std::move(__t))...); - } - - template - _LIBCPP_HIDE_FROM_ABI tuple - __transform_tuple(integral_constant, tuple<_Args...>&& __t, index_sequence<_Is...>) { - using _Tup = tuple; - return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...); - } - - template - _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&> - __transform_tuple(integral_constant, tuple<_Args...>&& __t, index_sequence<_Is...>) { - using _Tup = tuple<_Args&&..., polymorphic_allocator&>; - return _Tup(std::get<_Is>(std::move(__t))..., *this); - } - _LIBCPP_HIDE_FROM_ABI size_t __max_size() const noexcept { return numeric_limits::max() / sizeof(value_type); } diff --git a/libcxx/include/scoped_allocator b/libcxx/include/scoped_allocator index 74effc547f3e2..8e6dd38f1fed0 100644 --- a/libcxx/include/scoped_allocator +++ b/libcxx/include/scoped_allocator @@ -113,12 +113,15 @@ template # include <__cxx03/__config> #else # include <__config> +# include <__memory/allocator_arg_t.h> # include <__memory/allocator_traits.h> +# include <__memory/uses_allocator.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> # include <__type_traits/is_constructible.h> +# include <__type_traits/remove_cv.h> # include <__type_traits/remove_reference.h> # include <__utility/declval.h> # include <__utility/forward.h> @@ -421,23 +424,34 @@ public: # else template _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Args&&... __args) { - __construct(__uses_alloc_ctor<_Tp, inner_allocator_type&, _Args...>(), __p, std::forward<_Args>(__args)...); + using _OM = __outermost; + if constexpr (!uses_allocator<__remove_cv_t<_Tp>, inner_allocator_type>::value) { + static_assert(is_constructible<_Tp, _Args...>::value, + "If uses_allocator_v is false, T has to be constructible from arguments"); + allocator_traits::construct(_OM()(outer_allocator()), __p, std::forward<_Args>(__args)...); + } else if constexpr (is_constructible<_Tp, allocator_arg_t, const inner_allocator_type&, _Args...>::value) { + const auto& __inner_alloc = inner_allocator(); + allocator_traits::construct( + _OM()(outer_allocator()), __p, allocator_arg, __inner_alloc, std::forward<_Args>(__args)...); + } else if constexpr (is_constructible<_Tp, _Args..., const inner_allocator_type&>::value) { + const auto& __inner_alloc = inner_allocator(); + allocator_traits::construct( + _OM()(outer_allocator()), __p, std::forward<_Args>(__args)..., __inner_alloc); + } else { + static_assert(false, "If uses_allocator_v is true, T has to be allocator-constructible"); + } } template _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) { - typedef __outermost _OM; + using _OM = __outermost; allocator_traits::construct( _OM()(outer_allocator()), __p, piecewise_construct, - __transform_tuple(typename __uses_alloc_ctor< _T1, inner_allocator_type&, _Args1... >::type(), - std::move(__x), - __make_index_sequence()), - __transform_tuple(typename __uses_alloc_ctor< _T2, inner_allocator_type&, _Args2... >::type(), - std::move(__y), - __make_index_sequence())); + std::__transform_tuple_using_allocator<_T1>(inner_allocator(), std::move(__x)), + std::__transform_tuple_using_allocator<_T2>(inner_allocator(), std::move(__y))); } template @@ -481,46 +495,6 @@ private: _LIBCPP_HIDE_FROM_ABI explicit scoped_allocator_adaptor( outer_allocator_type&& __o, inner_allocator_type&& __i) _NOEXCEPT : _Base(std::move(__o), std::move(__i)) {} - template - _LIBCPP_HIDE_FROM_ABI void __construct(integral_constant, _Tp* __p, _Args&&... __args) { - typedef __outermost _OM; - allocator_traits::construct(_OM()(outer_allocator()), __p, std::forward<_Args>(__args)...); - } - - template - _LIBCPP_HIDE_FROM_ABI void __construct(integral_constant, _Tp* __p, _Args&&... __args) { - typedef __outermost _OM; - allocator_traits::construct( - _OM()(outer_allocator()), __p, allocator_arg, inner_allocator(), std::forward<_Args>(__args)...); - } - - template - _LIBCPP_HIDE_FROM_ABI void __construct(integral_constant, _Tp* __p, _Args&&... __args) { - typedef __outermost _OM; - allocator_traits::construct( - _OM()(outer_allocator()), __p, std::forward<_Args>(__args)..., inner_allocator()); - } - - template - _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> - __transform_tuple(integral_constant, tuple<_Args...>&& __t, __index_sequence<_Idx...>) { - return std::forward_as_tuple(std::get<_Idx>(std::move(__t))...); - } - - template - _LIBCPP_HIDE_FROM_ABI tuple - __transform_tuple(integral_constant, tuple<_Args...>&& __t, __index_sequence<_Idx...>) { - using _Tup = tuple; - return _Tup(allocator_arg, inner_allocator(), std::get<_Idx>(std::move(__t))...); - } - - template - _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., inner_allocator_type&> - __transform_tuple(integral_constant, tuple<_Args...>&& __t, __index_sequence<_Idx...>) { - using _Tup = tuple<_Args&&..., inner_allocator_type&>; - return _Tup(std::get<_Idx>(std::move(__t))..., inner_allocator()); - } - template friend class __scoped_allocator_storage; }; diff --git a/libcxx/include/tuple b/libcxx/include/tuple index be30ab5b2173d..27c13fa63e0a9 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -382,6 +382,11 @@ public: static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple"); } + template + _LIBCPP_HIDE_FROM_ABI __tuple_leaf(integral_constant, const _Alloc&, _Args&&...) { + static_assert(false, "If uses_allocator_v is true, T has to be allocator-constructible"); + } + template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc&) : __value_() { static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple"); @@ -456,6 +461,11 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) {} + template + _LIBCPP_HIDE_FROM_ABI __tuple_leaf(integral_constant, const _Alloc&, _Args&&...) { + static_assert(false, "If uses_allocator_v is true, T has to be allocator-constructible"); + } + template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc&) {} 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 index eac0452c04825..add6d419bf35e 100644 --- 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 @@ -44,15 +44,9 @@ void test_no_inner_alloc() { 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); } @@ -71,15 +65,8 @@ void test_no_inner_alloc() { 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 + assert((P.checkConstruct&&, std::tuple<>&&>( + CA, ptr))); A.destroy(ptr); std::free(ptr); } @@ -108,15 +95,9 @@ void test_with_inner_alloc() { 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); } @@ -140,15 +121,9 @@ void test_with_inner_alloc() { 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 index 6fbbea68afbbc..77d0a9e987d65 100644 --- 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 @@ -48,15 +48,9 @@ void test_no_inner_alloc() { 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); } @@ -79,15 +73,9 @@ void test_no_inner_alloc() { 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); } @@ -120,15 +108,9 @@ void test_with_inner_alloc() { 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); } @@ -156,15 +138,9 @@ void test_with_inner_alloc() { 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 index 79cb05ebee049..2db607070ae9e 100644 --- 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 @@ -47,15 +47,9 @@ void test_no_inner_alloc() { A.construct(ptr, std::piecewise_construct, std::forward_as_tuple(x), 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); } @@ -76,15 +70,9 @@ void test_no_inner_alloc() { A.construct(ptr, std::piecewise_construct, std::forward_as_tuple(std::move(x)), 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,15 +103,9 @@ void test_with_inner_alloc() { A.construct(ptr, std::piecewise_construct, std::forward_as_tuple(x), 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); } @@ -150,15 +132,9 @@ void test_with_inner_alloc() { ptr, std::piecewise_construct, std::forward_as_tuple(std::move(x)), 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 index f6bd83550d271..eafe3eddbb523 100644 --- 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 @@ -48,15 +48,9 @@ void test_no_inner_alloc() { 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); } @@ -79,15 +73,9 @@ void test_no_inner_alloc() { 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); } @@ -120,15 +108,9 @@ void test_with_inner_alloc() { 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); } @@ -156,15 +138,9 @@ void test_with_inner_alloc() { 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 index 66c3259072e64..3c9f8b8e7a407 100644 --- 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 @@ -46,15 +46,9 @@ void test_no_inner_alloc() { 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); } @@ -75,15 +69,9 @@ void test_no_inner_alloc() { 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); } @@ -114,15 +102,9 @@ void test_with_inner_alloc() { 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); } @@ -148,15 +130,9 @@ void test_with_inner_alloc() { 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 index 0ae3e6715606f..9022c1b5d9d8f 100644 --- 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 @@ -59,10 +59,11 @@ void test_bullet_one() { POuter.reset(); } +// `const` is added per LWG3187 // Otherwise, if uses_allocator_v is true and -// is_constructible_v is +// is_constructible_v is // true, calls OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p, -// allocator_arg, inner_allocator(), std::forward(args)...). +// allocator_arg, as_const(inner_allocator()), std::forward(args)...). void test_bullet_two() { using VoidAlloc2 = CountingAllocator; @@ -83,13 +84,8 @@ void test_bullet_two() { 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 + assert( + (POuter.checkConstruct(O, ptr))); A.destroy(ptr); ::operator delete((void*)ptr); } @@ -97,10 +93,11 @@ void test_bullet_two() { POuter.reset(); } +// `const` is added per LWG3187 // Otherwise, if uses_allocator_v is true and -// is_constructible_v is true, calls +// is_constructible_v is true, calls // OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p, -// std::forward(args)..., inner_allocator()). +// std::forward(args)..., as_const(inner_allocator())). void test_bullet_three() { using VoidAlloc2 = CountingAllocator; @@ -121,11 +118,7 @@ void test_bullet_three() { 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 + assert((POuter.checkConstruct(O, ptr))); A.destroy(ptr); ::operator delete((void*)ptr); } diff --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp index 701381fde5adb..b74e5ec879621 100644 --- a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp +++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp @@ -30,10 +30,10 @@ template struct EvilAlloc { explicit EvilAlloc() : inner_(std::pmr::null_memory_resource()) {} - EvilAlloc(std::pmr::polymorphic_allocator& a) : inner_(a) {} + EvilAlloc(std::pmr::polymorphic_allocator&) = delete; EvilAlloc(std::pmr::polymorphic_allocator&& a) : inner_(a) {} - EvilAlloc(std::pmr::polymorphic_allocator const& a) = delete; - EvilAlloc(std::pmr::polymorphic_allocator const&& a) = delete; + EvilAlloc(std::pmr::polymorphic_allocator const& a) : inner_(a) {} + EvilAlloc(std::pmr::polymorphic_allocator const&&) = delete; using value_type = T; template diff --git a/libcxx/test/support/uses_alloc_types.h b/libcxx/test/support/uses_alloc_types.h index 66746960fc87c..e0a1903becd00 100644 --- a/libcxx/test/support/uses_alloc_types.h +++ b/libcxx/test/support/uses_alloc_types.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "test_macros.h" #include "test_workarounds.h" @@ -335,4 +336,19 @@ class NotUsesAllocator : public UsesAllocatorTestBase(args)...) {} }; +//////////////////////////////////////////////////////////////////////////////// + +// P0591R4 changed the uses-allocator construction to pack `allocator_arg` and `piecewise_construct` into +// a `tuple` by value first, so `allocator_traits::construct` receives `allocator_arg_t&&` and +// `piecewise_construct_t&&` respectively. +// Until C++20, `allocator_arg` and `piecewise_construct` were directly passed to `allocator_traits::construct` +// and thus the latter received `const allocator_arg_t&` and `const piecewise_construct_t&`. +#if TEST_STD_VER >= 20 +using allocator_arg_ref_t = std::allocator_arg_t&&; +using piecewise_construct_ref_t = std::piecewise_construct_t&&; +#else +using allocator_arg_ref_t = const std::allocator_arg_t&; +using piecewise_construct_ref_t = const std::piecewise_construct_t&; +#endif + #endif /* USES_ALLOC_TYPES_H */