Skip to content

[libc++] Fix missing declarations of uses_allocator_construction_args #67044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 122 additions & 129 deletions libcxx/include/__memory/uses_allocator_construction.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,104 +40,8 @@ inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
template <class _Tp>
inline constexpr bool __is_cv_std_pair = __is_std_pair<remove_cv_t<_Tp>>;

template <class _Type, class _Alloc, class... _Args, __enable_if_t<!__is_cv_std_pair<_Type>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(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> &&
is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) {
return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __alloc, std::forward<_Args>(__args)...);
} else if constexpr (uses_allocator_v<remove_cv_t<_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<Type> is true, the type has to be allocator-constructible");
}
}

template <class _Pair, class _Alloc, class _Tuple1, class _Tuple2, __enable_if_t<__is_cv_std_pair<_Pair>, 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<typename _Pair::first_type>(
__alloc, std::forward<decltype(__args1)>(__args1)...);
},
std::forward<_Tuple1>(__x)),
std::apply(
[&__alloc](auto&&... __args2) {
return std::__uses_allocator_construction_args<typename _Pair::second_type>(
__alloc, std::forward<decltype(__args2)>(__args2)...);
},
std::forward<_Tuple2>(__y)));
}

template <class _Pair, class _Alloc, __enable_if_t<__is_cv_std_pair<_Pair>, 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 <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, 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 >= 23
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, 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 <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, 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 <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, 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 >= 23
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, 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))));
}

template <class _Pair, class _Alloc, __pair_like_no_subrange _PairLike, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, _PairLike&& __p) noexcept {
return std::__uses_allocator_construction_args<_Pair>(
__alloc,
piecewise_construct,
std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))),
std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p))));
}
# endif
template <class _Tp, class = void>
struct __uses_allocator_construction_args;

namespace __uses_allocator_detail {

Expand Down Expand Up @@ -165,54 +69,143 @@ inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !_

} // namespace __uses_allocator_detail

template < class _Pair,
class _Alloc,
class _Type,
__enable_if_t<__uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept;

template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args);

template < class _Pair,
class _Alloc,
class _Type,
__enable_if_t< __uses_allocator_detail::__uses_allocator_constraints<_Pair, _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>;
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
__apply(const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept {
return std::make_tuple(
piecewise_construct,
std::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(
[&__alloc](auto&&... __args2) {
return __uses_allocator_construction_args<typename _Pair::second_type>::__apply(
__alloc, std::forward<decltype(__args2)>(__args2)...);
},
std::forward<_Tuple2>(__y)));
}

_LIBCPP_HIDDEN constexpr auto __do_construct(const _PairMutable& __pair) const {
return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair);
}
template <class _Alloc>
static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(__alloc, piecewise_construct, tuple<>{}, tuple<>{});
}

_LIBCPP_HIDDEN constexpr auto __do_construct(_PairMutable&& __pair) const {
return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair));
}
template <class _Alloc, class _Up, class _Vp>
static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__alloc,
piecewise_construct,
std::forward_as_tuple(std::forward<_Up>(__u)),
std::forward_as_tuple(std::forward<_Vp>(__v)));
}

const _Alloc& __alloc_;
_Type& __value_;
# if _LIBCPP_STD_VER >= 23
template <class _Alloc, class _Up, class _Vp>
static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, 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));
}
# endif

_LIBCPP_HIDDEN constexpr operator _PairMutable() const { return __do_construct(std::forward<_Type>(__value_)); }
};
template <class _Alloc, class _Up, class _Vp>
static _LIBCPP_HIDE_FROM_ABI constexpr 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));
}

return std::make_tuple(__pair_constructor{__alloc, __value});
}
template <class _Alloc, class _Up, class _Vp>
static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__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 >= 23
template <class _Alloc, class _Up, class _Vp>
static _LIBCPP_HIDE_FROM_ABI constexpr 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(std::get<0>(std::move(__pair))),
std::forward_as_tuple(std::get<1>(std::move(__pair))));
}

template < class _Alloc, __pair_like_no_subrange _PairLike>
static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _PairLike&& __p) noexcept {
return __uses_allocator_construction_args<_Pair>::__apply(
__alloc,
piecewise_construct,
std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))),
std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p))));
}
# endif

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 {
struct __pair_constructor {
using _PairMutable = remove_cv_t<_Pair>;

_LIBCPP_HIDDEN constexpr 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 {
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_)); }
};

return std::make_tuple(__pair_constructor{__alloc, __value});
}
};

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 {
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> &&
is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) {
return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __alloc, std::forward<_Args>(__args)...);
} else if constexpr (uses_allocator_v<remove_cv_t<_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<Type> is true, the type has to be allocator-constructible");
}
}
};

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>(
std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
__uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
}

template <class _Type, class _Alloc, class... _Args>
_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<decltype(__xs)>(__xs)...); },
std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
__uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
}

#endif // _LIBCPP_STD_VER >= 17
Expand All @@ -221,8 +214,8 @@ __uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _

template <class _Type, class _Alloc, class... _Args>
_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)...);
-> decltype(__uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...)) {
return /*--*/ __uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...);
}

template <class _Type, class _Alloc, class... _Args>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,63 @@ constexpr void testOne() {
assert(std::get<2>(std::get<1>(ret)) == 3);
assert(std::get<0>(std::get<2>(ret)) == 4);
}
{
// Tests for ensuring forward declarations of uses_allocator_construction_args
// See https://github.com/llvm/llvm-project/issues/66714.
{
using NestedPairType = std::pair<int, std::pair<int, UsesAllocArgT>>;
std::same_as<std::tuple<
std::piecewise_construct_t,
std::tuple<>,
std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<std::allocator_arg_t, const Alloc&>>>> auto
ret = test_uses_allocator_construction_args<NestedPairType>(a);
(void)ret;
}
{
using NestedPairType = std::pair<int, std::pair<UsesAllocArgT, int>>;
std::same_as<std::tuple<
std::piecewise_construct_t,
std::tuple<>,
std::tuple<std::piecewise_construct_t, std::tuple<std::allocator_arg_t, const Alloc&>, std::tuple<>>>> auto
ret = test_uses_allocator_construction_args<NestedPairType>(a);
(void)ret;
}
{
using PairType = std::pair<int, int>;
int up = 1;
int vp = 2;

std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<int&&>, std::tuple<int&&>>> auto ret =
test_uses_allocator_construction_args<PairType>(a, std::move(up), std::move(vp));
(void)ret;
}
{
using PairType = const std::pair<int, int>;
PairType p(1, 2);

std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<const int&>, std::tuple<const int&>>> auto ret =
test_uses_allocator_construction_args<PairType>(a, p);
(void)ret;
}
{
using PairType = std::pair<int, int>;
PairType p(1, 2);

std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<int&&>, std::tuple<int&&>>> auto ret =
test_uses_allocator_construction_args<PairType>(a, std::move(p));
(void)ret;
}
#if TEST_STD_VER >= 23
{
using PairType = const std::pair<int, int>;
PairType p(1, 2);

std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<const int&&>, std::tuple<const int&&>>> auto ret =
test_uses_allocator_construction_args<PairType>(a, std::move(p));
(void)ret;
}
#endif
}
#if TEST_STD_VER >= 23
{
std::pair p{3, 4};
Expand Down
Loading