[libcxx-commits] [libcxx] [libc++] LWG3187: P0591R4 reverted DR 2586 fixes to `scoped_allocator_adaptor::construct()` (PR #152424)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Nov 27 02:11:52 PST 2025
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/152424
>From 322b522f990b9a5db302edad699aa0c737a9a5d5 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Thu, 27 Nov 2025 17:34:46 +0800
Subject: [PATCH] [libc++] LWG3187: P0591R4 reverted DR 2586 fixes to
`scoped_allocator_adaptor::construct()`
Applying it (adding missing `const``) to pre-C++20 dispatching
mechanisms.
Also
- make dispatch mechanisms in pre-C++20 `construct` more consistent,
- add fallback dispatching and overloads to emit better error messages,
and
- partially implement LWG4312.
---
libcxx/docs/Status/Cxx20Issues.csv | 2 +-
libcxx/include/__memory/allocator_arg_t.h | 28 +--
.../__memory/uses_allocator_construction.h | 159 +++++++++++++++---
.../__memory_resource/polymorphic_allocator.h | 42 +----
libcxx/include/scoped_allocator | 92 +++++-----
libcxx/include/tuple | 10 ++
.../construct_pair.pass.cpp | 35 +---
.../construct_pair_const_lvalue_pair.pass.cpp | 32 +---
.../construct_pair_piecewise.pass.cpp | 32 +---
.../construct_pair_rvalue.pass.cpp | 32 +---
.../construct_pair_values.pass.cpp | 32 +---
.../construct_type.pass.cpp | 22 +--
.../construct_piecewise_pair_evil.pass.cpp | 6 +-
libcxx/test/support/uses_alloc_types.h | 13 ++
14 files changed, 245 insertions(+), 292 deletions(-)
diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index 3d01ff5bbbdfb..fe16ba2acad73 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -151,7 +151,7 @@
"`LWG3184 <https://wg21.link/LWG3184>`__","Inconsistencies in ``bind_front``\ wording","2019-07 (Cologne)","|Complete|","13","`#103850 <https://github.com/llvm/llvm-project/issues/103850>`__",""
"`LWG3185 <https://wg21.link/LWG3185>`__","Uses-allocator construction functions missing ``constexpr``\ and ``noexcept``\ ","2019-07 (Cologne)","|Complete|","16","`#103851 <https://github.com/llvm/llvm-project/issues/103851>`__",""
"`LWG3186 <https://wg21.link/LWG3186>`__","``ranges``\ removal, partition, and ``partial_sort_copy``\ algorithms discard useful information","2019-07 (Cologne)","|Complete|","15","`#103852 <https://github.com/llvm/llvm-project/issues/103852>`__",""
-"`LWG3187 <https://wg21.link/LWG3187>`__","`P0591R4 <https://wg21.link/p0591r4>`__ reverted DR 2586 fixes to ``scoped_allocator_adaptor::construct()``\ ","2019-07 (Cologne)","","","`#100256 <https://github.com/llvm/llvm-project/issues/100256>`__",""
+"`LWG3187 <https://wg21.link/LWG3187>`__","`P0591R4 <https://wg21.link/p0591r4>`__ reverted DR 2586 fixes to ``scoped_allocator_adaptor::construct()``\ ","2019-07 (Cologne)","|Complete|","22","`#100256 <https://github.com/llvm/llvm-project/issues/100256>`__",""
"`LWG3191 <https://wg21.link/LWG3191>`__","``std::ranges::shuffle``\ synopsis does not match algorithm definition","2019-07 (Cologne)","|Complete|","15","`#103853 <https://github.com/llvm/llvm-project/issues/103853>`__",""
"`LWG3196 <https://wg21.link/LWG3196>`__","``std::optional<T>``\ is ill-formed is ``T``\ is an array","2019-07 (Cologne)","|Complete|","","`#103854 <https://github.com/llvm/llvm-project/issues/103854>`__",""
"`LWG3198 <https://wg21.link/LWG3198>`__","Bad constraint on ``std::span::span()``\ ","2019-07 (Cologne)","|Complete|","","`#103856 <https://github.com/llvm/llvm-project/issues/103856>`__",""
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 <class _Tp, class _Alloc, class... _Args>
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 <class _Tp, class _Alloc, class... _Args>
struct __uses_alloc_ctor : integral_constant<int, __uses_alloc_ctor_imp<_Tp, _Alloc, _Args...>::value> {};
-template <class _Tp, class _Allocator, class... _Args>
-inline _LIBCPP_HIDE_FROM_ABI void
-__user_alloc_construct_impl(integral_constant<int, 0>, _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 <class _Tp, class _Allocator, class... _Args>
-inline _LIBCPP_HIDE_FROM_ABI void
-__user_alloc_construct_impl(integral_constant<int, 1>, _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 <class _Tp, class _Allocator, class... _Args>
-inline _LIBCPP_HIDE_FROM_ABI void
-__user_alloc_construct_impl(integral_constant<int, 2>, _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..e39dce99c0292 100644
--- a/libcxx/include/__memory/uses_allocator_construction.h
+++ b/libcxx/include/__memory/uses_allocator_construction.h
@@ -10,12 +10,18 @@
#define _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
#include <__config>
+#include <__cstddef/size_t.h>
+#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/invoke.h>
+#include <__type_traits/is_constructible.h>
#include <__type_traits/remove_cv.h>
+#include <__type_traits/remove_cvref.h>
#include <__utility/declval.h>
+#include <__utility/integer_sequence.h>
#include <__utility/pair.h>
#include <__utility/piecewise_construct.h>
#include <tuple>
@@ -29,7 +35,43 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-#if _LIBCPP_STD_VER >= 17
+#if !defined(_LIBCPP_CXX03_LANG) && _LIBCPP_STD_VER < 14
+
+template <class _Alloc, class... _Args, size_t... _Is>
+_LIBCPP_HIDE_FROM_ABI void __transform_tuple_using_allocator_impl(
+ integral_constant<int, -1>, const _Alloc&, tuple<_Args...>&&, __index_sequence<_Is...>) {
+ static_assert(false, "If uses_allocator_v<T, A> is true, T has to be allocator-constructible");
+}
+
+template <class _Alloc, class... _Args, size_t... _Is>
+_LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> __transform_tuple_using_allocator_impl(
+ integral_constant<int, 0>, const _Alloc&, tuple<_Args...>&& __t, __index_sequence<_Is...>) {
+ return tuple<_Args&&...>(std::move(__t));
+}
+
+template <class _Alloc, class... _Args, size_t... _Is>
+_LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t, const _Alloc&, _Args&&...> __transform_tuple_using_allocator_impl(
+ integral_constant<int, 1>, const _Alloc& __a, tuple<_Args...>&& __t, __index_sequence<_Is...>) {
+ return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __a, std::get<_Is>(std::move(__t))...);
+}
+
+template <class _Alloc, class... _Args, size_t... _Is>
+_LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., const _Alloc&> __transform_tuple_using_allocator_impl(
+ integral_constant<int, 2>, const _Alloc& __a, tuple<_Args...>&& __t, __index_sequence<_Is...>) {
+ return tuple<_Args&&..., const _Alloc&>(std::get<_Is>(std::move(__t))..., __a);
+}
+
+template <class _Tp, class _Alloc, class... _Args>
+_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<sizeof...(_Args)>{})) {
+ return std::__transform_tuple_using_allocator_impl(
+ __uses_alloc_ctor<_Tp, _Alloc, _Args...>{}, __a, std::move(__t), __make_index_sequence<sizeof...(_Args)>{});
+}
+
+#endif // !defined(_LIBCPP_CXX03_LANG) && _LIBCPP_STD_VER < 14
+
+#if _LIBCPP_STD_VER >= 14
template <class _Tp>
inline constexpr bool __is_cv_std_pair = __is_pair_v<remove_cv_t<_Tp>>;
@@ -40,17 +82,13 @@ struct __uses_allocator_construction_args;
namespace __uses_allocator_detail {
template <class _Ap, class _Bp>
-void __fun(const pair<_Ap, _Bp>&);
-
-template <class _Tp>
-decltype(__uses_allocator_detail::__fun(std::declval<_Tp>()), true_type()) __convertible_to_const_pair_ref_impl(int);
-
-template <class>
-false_type __convertible_to_const_pair_ref_impl(...);
+void __pair_taker(const pair<_Ap, _Bp>&);
+template <class, class = void>
+inline constexpr bool __convertible_to_const_pair_ref = false;
template <class _Tp>
-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::__pair_taker(std::declval<_Tp>()))> = true;
# if _LIBCPP_STD_VER >= 23
template <class _Tp, class _Up>
@@ -61,25 +99,71 @@ template <class _Tp, class _Up>
inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !__convertible_to_const_pair_ref<_Up>;
# endif
+# if _LIBCPP_STD_VER < 17
+template <class _Tp>
+struct __construction_fn {
+ template <class... _Args>
+ static _LIBCPP_HIDE_FROM_ABI constexpr _Tp operator()(_Args&&... __args) {
+ static_assert(is_constructible_v<_Tp, _Args...>, "undesired C-style cast used");
+ return _Tp(std::forward<_Args&&>(__args)...);
+ }
+};
+
+template <class _Fn, class _Tuple, size_t... _Ip>
+_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) __apply_impl(_Fn&& __fn, _Tuple&& __t, index_sequence<_Ip...>) {
+ return std::__invoke(std::forward<_Fn>(__fn), std::get<_Ip>(std::forward<_Tuple>(__t))...);
+}
+# endif // _LIBCPP_STD_VER < 17
+
+template <class _Fn, class _Tuple>
+_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) __apply(_Fn&& __fn, _Tuple&& __t) {
+# if _LIBCPP_STD_VER >= 17
+ return std::apply(std::forward<_Fn>(__fn), std::forward<_Tuple>(__t));
+# else
+ return __uses_allocator_detail::__apply_impl(
+ std::forward<_Fn>(__fn), std::forward<_Tuple>(__t), std::make_index_sequence<__remove_cvref_t<_Tuple>>{});
+# endif
+}
+
+template <class _Tp, class _Tuple>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple(_Tuple&& __t) {
+# if _LIBCPP_STD_VER >= 17
+ return std::make_from_tuple<_Tp>(std::forward<_Tuple>(__t));
+# else
+ return __uses_allocator_detail::__apply_impl(
+ __construction_fn<_Tp>{}, std::forward<_Tuple>(__t), std::make_index_sequence<__remove_cvref_t<_Tuple>>{});
+# endif
+}
+
+template <class _Tp, class... _Args, class = decltype(::new (std::declval<void*>()) _Tp(std::declval<_Args>()...))>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* __construct_at_nocv(_Tp* __location, _Args&&... __args) {
+ return std::__construct_at(const_cast<remove_cv_t<_Tp>*>(__location), std::forward<_Args>(__args)...);
+}
+
} // namespace __uses_allocator_detail
template <class _Type, class _Alloc, class... _Args>
-_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args);
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Type
+__make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args);
template <class _Pair>
struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<_Pair>>> {
template <class _Alloc, class _Tuple1, class _Tuple2>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto
__apply(const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept {
return std::make_tuple(
+# if _LIBCPP_STD_VER >= 20
piecewise_construct,
- std::apply(
+# else // _LIBCPP_STD_VER >= 20
+ std::ref(piecewise_construct),
+# endif // _LIBCPP_STD_VER >= 20
+ __uses_allocator_detail::__apply(
[&__alloc](auto&&... __args1) {
return __uses_allocator_construction_args<typename _Pair::first_type>::__apply(
__alloc, std::forward<decltype(__args1)>(__args1)...);
},
std::forward<_Tuple1>(__x)),
- std::apply(
+ __uses_allocator_detail::__apply(
[&__alloc](auto&&... __args2) {
return __uses_allocator_construction_args<typename _Pair::second_type>::__apply(
__alloc, std::forward<decltype(__args2)>(__args2)...);
@@ -88,12 +172,13 @@ struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<
}
template <class _Alloc>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto __apply(const _Alloc& __alloc) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(__alloc, piecewise_construct, tuple<>{}, tuple<>{});
}
template <class _Alloc, class _Up, class _Vp>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto
+ __apply(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__alloc,
piecewise_construct,
@@ -110,13 +195,15 @@ struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<
# endif
template <class _Alloc, class _Up, class _Vp>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_CONSTEXPR_SINCE_CXX17 auto __apply(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
}
template <class _Alloc, class _Up, class _Vp>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto
+ __apply(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__alloc,
piecewise_construct,
@@ -135,7 +222,8 @@ struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<
}
template < class _Alloc, __pair_like_no_subrange _PairLike>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _PairLike&& __p) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto
+ __apply(const _Alloc& __alloc, _PairLike&& __p) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__alloc,
piecewise_construct,
@@ -147,22 +235,25 @@ struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<
template <class _Alloc,
class _Type,
__enable_if_t<__uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int> = 0>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Type&& __value) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_CONSTEXPR_SINCE_CXX17 auto __apply(const _Alloc& __alloc, _Type&& __value) noexcept {
struct __pair_constructor {
using _PairMutable = remove_cv_t<_Pair>;
- _LIBCPP_HIDDEN constexpr auto __do_construct(const _PairMutable& __pair) const {
+ _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR_SINCE_CXX17 auto __do_construct(const _PairMutable& __pair) const {
return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair);
}
- _LIBCPP_HIDDEN constexpr auto __do_construct(_PairMutable&& __pair) const {
+ _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR_SINCE_CXX17 auto __do_construct(_PairMutable&& __pair) const {
return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair));
}
const _Alloc& __alloc_;
_Type& __value_;
- _LIBCPP_HIDDEN constexpr operator _PairMutable() const { return __do_construct(std::forward<_Type>(__value_)); }
+ _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR_SINCE_CXX17 operator _PairMutable() const {
+ return __do_construct(std::forward<_Type>(__value_));
+ }
};
return std::make_tuple(__pair_constructor{__alloc, __value});
@@ -172,7 +263,8 @@ struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<
template <class _Type>
struct __uses_allocator_construction_args<_Type, __enable_if_t<!__is_cv_std_pair<_Type>>> {
template <class _Alloc, class... _Args>
- static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Args&&... __args) noexcept {
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto
+ __apply(const _Alloc& __alloc, _Args&&... __args) noexcept {
if constexpr (!uses_allocator_v<remove_cv_t<_Type>, _Alloc> && is_constructible_v<_Type, _Args...>) {
return std::forward_as_tuple(std::forward<_Args>(__args)...);
} else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
@@ -189,20 +281,31 @@ struct __uses_allocator_construction_args<_Type, __enable_if_t<!__is_cv_std_pair
};
template <class _Type, class _Alloc, class... _Args>
-_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) {
- return std::make_from_tuple<_Type>(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Type
+__make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) {
+ return __uses_allocator_detail::__make_from_tuple<_Type>(
__uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
}
template <class _Type, class _Alloc, class... _Args>
-_LIBCPP_HIDE_FROM_ABI constexpr _Type*
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _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<decltype(__xs)>(__xs)...); },
__uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
}
-#endif // _LIBCPP_STD_VER >= 17
+template <class _Type, class _Alloc, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Type*
+__uninitialized_construct_using_allocator_nocv(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) {
+ return std::apply(
+ [&__ptr](auto&&... __xs) {
+ return __uses_allocator_detail::__construct_at_nocv(__ptr, std::forward<decltype(__xs)>(__xs)...);
+ },
+ __uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
+}
+
+#endif // _LIBCPP_STD_VER >= 14
#if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h
index 9a351199b5b16..1bb7ef4981ffa 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 <limits>
@@ -122,24 +128,14 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator {
template <class _Tp, class... _Ts>
_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::__uninitialized_construct_using_allocator_nocv(__p, std::forward<_Ts>(__args)...);
}
template <class _T1, class _T2, class... _Args1, class... _Args2>
_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<sizeof...(_Args1)>()),
- __transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(),
- std::move(__y),
- make_index_sequence<sizeof...(_Args2)>()));
+ std::__uninitialized_construct_using_allocator_nocv(
+ __p, piecewise_construct, tuple<_Args1&&...>(std::move(__x)), tuple<_Args2&&...>(std::move(__y)));
}
template <class _T1, class _T2>
@@ -193,26 +189,6 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator {
# endif
private:
- template <class... _Args, size_t... _Is>
- _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...>
- __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, index_sequence<_Is...>) {
- return std::forward_as_tuple(std::get<_Is>(std::move(__t))...);
- }
-
- template <class... _Args, size_t... _Is>
- _LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>
- __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, index_sequence<_Is...>) {
- using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>;
- return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...);
- }
-
- template <class... _Args, size_t... _Is>
- _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&>
- __transform_tuple(integral_constant<int, 2>, 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<size_t>::max() / sizeof(value_type);
}
diff --git a/libcxx/include/scoped_allocator b/libcxx/include/scoped_allocator
index 74effc547f3e2..5ef038ac45177 100644
--- a/libcxx/include/scoped_allocator
+++ b/libcxx/include/scoped_allocator
@@ -113,12 +113,15 @@ template <class OuterA1, class OuterA2, class... InnerAllocs>
# 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,56 @@ public:
# else
template <class _Tp, class... _Args>
_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<outer_allocator_type>;
+# if _LIBCPP_STD_VER >= 14
+ __uses_allocator_detail::__apply(
+ [__ptr, this](auto&&... __newargs) {
+ allocator_traits<typename _OM::type>::construct(
+ _OM()(outer_allocator()), __ptr, std::forward<decltype(__newargs)>(__newargs)...);
+ },
+ __uses_allocator_construction_args<_Type>::__apply(inner_allocator(), std::forward<_Args>(__args)...));
+# else
+ if constexpr (!uses_allocator<__remove_cv_t<_Tp>, inner_allocator_type>::value) {
+ static_assert(is_constructible<_Tp, _Args...>::value,
+ "If uses_allocator_v<T, polymorphic_allocator> is false, T has to be constructible from arguments");
+ allocator_traits<typename _OM::type>::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<typename _OM::type>::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<typename _OM::type>::construct(
+ _OM()(outer_allocator()), __p, std::forward<_Args>(__args)..., __inner_alloc);
+ } else {
+ static_assert(false, "If uses_allocator_v<T, inner_allocator_type> is true, T has to be allocator-constructible");
+ }
+# endif
}
template <class _T1, class _T2, class... _Args1, class... _Args2>
_LIBCPP_HIDE_FROM_ABI void
construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) {
- typedef __outermost<outer_allocator_type> _OM;
+ using _OM = __outermost<outer_allocator_type>;
+# if _LIBCPP_STD_VER >= 14
+ __uses_allocator_detail::__apply(
+ [__ptr, this](auto&&... __newargs) {
+ allocator_traits<typename _OM::type>::construct(
+ _OM()(outer_allocator()), __ptr, std::forward<decltype(__newargs)>(__newargs)...);
+ },
+ __uses_allocator_construction_args<pair<_T1, _T2>>::__apply(
+ inner_allocator(),
+ piecewise_construct,
+ tuple<_Args1&&...>(std::move(__x)),
+ tuple<_Args2&&...>(std::move(__y))));
+# else
allocator_traits<typename _OM::type>::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<sizeof...(_Args1)>()),
- __transform_tuple(typename __uses_alloc_ctor< _T2, inner_allocator_type&, _Args2... >::type(),
- std::move(__y),
- __make_index_sequence<sizeof...(_Args2)>()));
+ std::__transform_tuple_using_allocator<_T1>(inner_allocator(), std::move(__x)),
+ std::__transform_tuple_using_allocator<_T2>(inner_allocator(), std::move(__y)));
+# endif
}
template <class _T1, class _T2>
@@ -481,46 +517,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 <class _Tp, class... _Args>
- _LIBCPP_HIDE_FROM_ABI void __construct(integral_constant<int, 0>, _Tp* __p, _Args&&... __args) {
- typedef __outermost<outer_allocator_type> _OM;
- allocator_traits<typename _OM::type>::construct(_OM()(outer_allocator()), __p, std::forward<_Args>(__args)...);
- }
-
- template <class _Tp, class... _Args>
- _LIBCPP_HIDE_FROM_ABI void __construct(integral_constant<int, 1>, _Tp* __p, _Args&&... __args) {
- typedef __outermost<outer_allocator_type> _OM;
- allocator_traits<typename _OM::type>::construct(
- _OM()(outer_allocator()), __p, allocator_arg, inner_allocator(), std::forward<_Args>(__args)...);
- }
-
- template <class _Tp, class... _Args>
- _LIBCPP_HIDE_FROM_ABI void __construct(integral_constant<int, 2>, _Tp* __p, _Args&&... __args) {
- typedef __outermost<outer_allocator_type> _OM;
- allocator_traits<typename _OM::type>::construct(
- _OM()(outer_allocator()), __p, std::forward<_Args>(__args)..., inner_allocator());
- }
-
- template <class... _Args, size_t... _Idx>
- _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...>
- __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __index_sequence<_Idx...>) {
- return std::forward_as_tuple(std::get<_Idx>(std::move(__t))...);
- }
-
- template <class... _Args, size_t... _Idx>
- _LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t, inner_allocator_type&, _Args&&...>
- __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __index_sequence<_Idx...>) {
- using _Tup = tuple<allocator_arg_t, inner_allocator_type&, _Args&&...>;
- return _Tup(allocator_arg, inner_allocator(), std::get<_Idx>(std::move(__t))...);
- }
-
- template <class... _Args, size_t... _Idx>
- _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., inner_allocator_type&>
- __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __index_sequence<_Idx...>) {
- using _Tup = tuple<_Args&&..., inner_allocator_type&>;
- return _Tup(std::get<_Idx>(std::move(__t))..., inner_allocator());
- }
-
template <class...>
friend class __scoped_allocator_storage;
};
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index caa473012a7c4..964a6ec120187 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 <class _Alloc, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI __tuple_leaf(integral_constant<int, -1>, const _Alloc&, _Args&&...) {
+ static_assert(false, "If uses_allocator_v<T, A> is true, T has to be allocator-constructible");
+ }
+
template <class _Alloc>
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, 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 <class _Alloc, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI __tuple_leaf(integral_constant<int, -1>, const _Alloc&, _Args&&...) {
+ static_assert(false, "If uses_allocator_v<T, A> is true, T has to be allocator-constructible");
+ }
+
template <class _Alloc>
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, 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::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&>&&,
std::tuple<const SA&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&>&&,
- std::tuple<SA&>&& >(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::piecewise_construct_t&&, std::tuple<std::allocator_arg_t, const SA&>&&, std::tuple<>&& >(
- CA, ptr)));
-#else
- assert(
- (P.checkConstruct<std::piecewise_construct_t const&, std::tuple<std::allocator_arg_t, SA&>&&, std::tuple<>&& >(
- CA, ptr)));
-#endif
+ assert((P.checkConstruct<piecewise_construct_ref_t, std::tuple<std::allocator_arg_t, const SA&>&&, 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::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&>&&,
std::tuple<const SAInner&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&>&&,
- std::tuple<SAInner&>&& >(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::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&>&&,
std::tuple<>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&>&&,
- 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<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_AllocLast, CA));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&, const SA&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&>&&,
- std::tuple<int const&, SA&>&& >(CA, ptr)));
-#endif
A.destroy(ptr);
std::free(ptr);
}
@@ -79,15 +73,9 @@ void test_no_inner_alloc() {
A.construct(ptr, in);
assert(checkConstruct<int const&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int const&>&&,
std::tuple<int const&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int const&>&&,
- std::tuple<int const&>&& >(CA, ptr)));
-#endif
A.destroy(ptr);
std::free(ptr);
}
@@ -120,15 +108,9 @@ void test_with_inner_alloc() {
A.construct(ptr, in);
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&>(ptr->second, UA_AllocLast));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int const&, const SAInner&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
- std::tuple<int const&, SAInner&>&& >(O, ptr)));
-#endif
A.destroy(ptr);
std::free(ptr);
}
@@ -156,15 +138,9 @@ void test_with_inner_alloc() {
A.construct(ptr, in);
assert(checkConstruct<int const&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int const&>&&,
std::tuple<int const&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int const&>&&,
- std::tuple<int const&>&& >(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<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&&, const SA&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&>&&,
- std::tuple<int const&&, SA&>&& >(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<int&&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&&>&&,
std::tuple<int const&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&&>&&,
- std::tuple<int const&>&& >(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<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int&&>(ptr->second, UA_AllocLast));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int&&, const SAInner&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
- std::tuple<int&&, SAInner&>&& >(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<int&&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&&>&&,
std::tuple<int const&&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&&>&&,
- std::tuple<int const&&>&& >(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<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&&, const SA&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&>&&,
- std::tuple<int const&&, SA&>&& >(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<int&&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&&>&&,
std::tuple<int const&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&&>&&,
- std::tuple<int const&>&& >(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<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int const&&, const SAInner&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
- std::tuple<int const&&, SAInner&>&& >(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<int&&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&&>&&,
std::tuple<int const&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&&>&&,
- std::tuple<int const&>&& >(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<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&&, const SA&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&>&&,
- std::tuple<int const&&, SA&>&& >(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<int&&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((P.checkConstruct<std::piecewise_construct_t&&,
+ assert((P.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SA&, int&&>&&,
std::tuple<int const&>&& >(CA, ptr)));
-#else
- assert((P.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SA&, int&&>&&,
- std::tuple<int const&>&& >(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<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int&&>(ptr->second, UA_AllocLast));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int&&, const SAInner&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
- std::tuple<int&&, SAInner&>&& >(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<int&&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&&>(ptr->second, UA_None));
-#if TEST_STD_VER >= 20
- assert((POuter.checkConstruct<std::piecewise_construct_t&&,
+ assert((POuter.checkConstruct<piecewise_construct_ref_t,
std::tuple<std::allocator_arg_t, const SAInner&, int&&>&&,
std::tuple<int const&&>&& >(O, ptr)));
-#else
- assert((POuter.checkConstruct<std::piecewise_construct_t const&,
- std::tuple<std::allocator_arg_t, SAInner&, int&&>&&,
- std::tuple<int const&&>&& >(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..b61bf5bdb2f4c 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,12 @@ void test_bullet_one() {
POuter.reset();
}
+// `const` is added per LWG3187
+// `allocator_arg_t{}` is used per LWG4312
// Otherwise, if uses_allocator_v<T, inner_allocator_type> is true and
-// is_constructible_v<T, allocator_arg_t, inner_allocator_type&, Args...> is
+// is_constructible_v<T, allocator_arg_t, const inner_allocator_type&, Args...> is
// true, calls OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p,
-// allocator_arg, inner_allocator(), std::forward<Args>(args)...).
+// allocator_arg_t{}, as_const(inner_allocator()), std::forward<Args>(args)...).
void test_bullet_two() {
using VoidAlloc2 = CountingAllocator<void, 2>;
@@ -83,13 +85,8 @@ void test_bullet_two() {
int const& cx = x;
A.construct(ptr, x, cx, std::move(x));
assert((checkConstruct<int&, int const&, int&&>(*ptr, UA_AllocArg, I)));
-#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::allocator_arg_t&&, const SA::inner_allocator_type&, int&, int const&, int&&>(
O, ptr)));
-#else
- assert((POuter.checkConstruct<std::allocator_arg_t const&, SA::inner_allocator_type&, int&, int const&, int&&>(
- O, ptr)));
-#endif
A.destroy(ptr);
::operator delete((void*)ptr);
}
@@ -97,10 +94,11 @@ void test_bullet_two() {
POuter.reset();
}
+// `const` is added per LWG3187
// Otherwise, if uses_allocator_v<T, inner_allocator_type> is true and
-// is_constructible_v<T, Args..., inner_allocator_type&> is true, calls
+// is_constructible_v<T, Args..., const inner_allocator_type&> is true, calls
// OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p,
-// std::forward<Args>(args)..., inner_allocator()).
+// std::forward<Args>(args)..., as_const(inner_allocator())).
void test_bullet_three() {
using VoidAlloc2 = CountingAllocator<void, 2>;
@@ -121,11 +119,7 @@ void test_bullet_three() {
int const& cx = x;
A.construct(ptr, x, cx, std::move(x));
assert((checkConstruct<int&, int const&, int&&>(*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<int&, int const&, int&&, const SA::inner_allocator_type&>(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 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 <class T>
struct EvilAlloc {
explicit EvilAlloc() : inner_(std::pmr::null_memory_resource()) {}
- EvilAlloc(std::pmr::polymorphic_allocator<T>& a) : inner_(a) {}
+ EvilAlloc(std::pmr::polymorphic_allocator<T>&) = delete;
EvilAlloc(std::pmr::polymorphic_allocator<T>&& a) : inner_(a) {}
- EvilAlloc(std::pmr::polymorphic_allocator<T> const& a) = delete;
- EvilAlloc(std::pmr::polymorphic_allocator<T> const&& a) = delete;
+ EvilAlloc(std::pmr::polymorphic_allocator<T> const& a) : inner_(a) {}
+ EvilAlloc(std::pmr::polymorphic_allocator<T> const&&) = delete;
using value_type = T;
template <class U>
diff --git a/libcxx/test/support/uses_alloc_types.h b/libcxx/test/support/uses_alloc_types.h
index 66746960fc87c..99bdcce3181a4 100644
--- a/libcxx/test/support/uses_alloc_types.h
+++ b/libcxx/test/support/uses_alloc_types.h
@@ -12,6 +12,7 @@
#include <cassert>
#include <cstdlib>
#include <memory>
+#include <utility>
#include "test_macros.h"
#include "test_workarounds.h"
@@ -335,4 +336,16 @@ class NotUsesAllocator : public UsesAllocatorTestBase<NotUsesAllocator<Alloc, Ar
NotUsesAllocator(Args&&... args) : Base(AllocLastTag{}, std::forward<Args>(args)...) {}
};
+////////////////////////////////////////////////////////////////////////////////
+
+// P0591R4 changed the uses-allocator construction to pack `piecewise_construct` into a `tuple` by value first, so
+// `allocator_traits<A>::construct` receives `piecewise_construct_t&&`.
+// Until C++20, `piecewise_construct` is directly passed to `allocator_traits<A>::construct` and thus the latter
+// received `const piecewise_construct_t&`.
+#if TEST_STD_VER >= 20
+using piecewise_construct_ref_t = std::piecewise_construct_t&&;
+#else
+using piecewise_construct_ref_t = const std::piecewise_construct_t&;
+#endif
+
#endif /* USES_ALLOC_TYPES_H */
More information about the libcxx-commits
mailing list