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..103385e7c4a4e 100644 --- a/libcxx/include/__memory/uses_allocator_construction.h +++ b/libcxx/include/__memory/uses_allocator_construction.h @@ -10,10 +10,12 @@ #define _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H #include <__config> +#include <__functional/reference_wrapper.h> #include <__memory/construct_at.h> #include <__memory/uses_allocator.h> #include <__tuple/tuple_like_no_subrange.h> #include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> #include <__type_traits/remove_cv.h> #include <__utility/declval.h> #include <__utility/pair.h> @@ -34,23 +36,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD template inline constexpr bool __is_cv_std_pair = __is_pair_v>; -template +template > struct __uses_allocator_construction_args; +# if _LIBCPP_STD_VER >= 20 +template +using __uses_allocator_construction_args_recursive _LIBCPP_NODEBUG = __uses_allocator_construction_args<_Tp>; +# else +template +using __uses_allocator_construction_args_recursive _LIBCPP_NODEBUG = __uses_allocator_construction_args<_Tp, false>; +# endif + namespace __uses_allocator_detail { template void __fun(const pair<_Ap, _Bp>&); +template +inline constexpr bool __convertible_to_const_pair_ref = false; 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; +inline constexpr bool + __convertible_to_const_pair_ref<_Tp, decltype(__uses_allocator_detail::__fun(std::declval<_Tp>()))> = true; # if _LIBCPP_STD_VER >= 23 template @@ -67,21 +73,25 @@ template _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args); template -struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<_Pair>>> { +struct __uses_allocator_construction_args<_Pair, true> { template static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept { return std::make_tuple( +# if _LIBCPP_STD_VER >= 20 piecewise_construct, +# else + std::ref(piecewise_construct), +# endif std::apply( [&__alloc](auto&&... __args1) { - return __uses_allocator_construction_args::__apply( + return __uses_allocator_construction_args_recursive::__apply( __alloc, std::forward(__args1)...); }, std::forward<_Tuple1>(__x)), std::apply( [&__alloc](auto&&... __args2) { - return __uses_allocator_construction_args::__apply( + return __uses_allocator_construction_args_recursive::__apply( __alloc, std::forward(__args2)...); }, std::forward<_Tuple2>(__y))); @@ -170,7 +180,7 @@ struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair< }; template -struct __uses_allocator_construction_args<_Type, __enable_if_t>> { +struct __uses_allocator_construction_args<_Type, false> { template static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Args&&... __args) noexcept { if constexpr (!uses_allocator_v, _Alloc> && is_constructible_v<_Type, _Args...>) { diff --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h index 9a351199b5b16..c3910ca70297a 100644 --- a/libcxx/include/__memory_resource/polymorphic_allocator.h +++ b/libcxx/include/__memory_resource/polymorphic_allocator.h @@ -14,9 +14,12 @@ #include <__cstddef/byte.h> #include <__cstddef/max_align_t.h> #include <__fwd/pair.h> +#include <__memory/construct_at.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/remove_cv.h> #include <__utility/exception_guard.h> #include <__utility/piecewise_construct.h> #include @@ -35,6 +38,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace pmr { +template +_LIBCPP_HIDE_FROM_ABI _Type* +__uninitialized_construct_using_allocator_nocv(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) { + return std::apply( + [__ptr_nocv = const_cast*>(__ptr)](auto&&... __xs) { + return std::__construct_at(__ptr_nocv, std::forward(__xs)...); + }, + __uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...)); +} + // [mem.poly.allocator.class] 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)...); + std::pmr::__uninitialized_construct_using_allocator_nocv(__p, *this, std::forward<_Ts>(__args)...); } template _LIBCPP_HIDE_FROM_ABI void 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::pmr::__uninitialized_construct_using_allocator_nocv( + __p, *this, piecewise_construct, tuple<_Args1&&...>(std::move(__x)), tuple<_Args2&&...>(std::move(__y))); } template @@ -193,26 +196,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/module.modulemap.in b/libcxx/include/module.modulemap.in index bbc2617835bc0..258589df6d645 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1686,7 +1686,10 @@ module std [system] { export * // TODO: Workaround for https://llvm.org/PR120108 } module uses_allocator { header "__memory/uses_allocator.h" } - module uses_allocator_construction { header "__memory/uses_allocator_construction.h" } + module uses_allocator_construction { + header "__memory/uses_allocator_construction.h" + export std.functional.reference_wrapper + } header "memory" export * diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 670b90fc7b3b9..7c3b1908c3f39 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -373,6 +373,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"); @@ -447,6 +452,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/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 b77734c28e12d..11eff1dc509e7 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