[libcxx-commits] [libcxx] [libc++] LWG 3821 uses_allocator_construction_args should have overload for pair-like (PR #66939)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Sep 21 14:32:43 PDT 2023
https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/66939
>From 5995e6c7e27194233a6f4714f2a5b39da9a3d953 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 20 Sep 2023 19:41:00 +0100
Subject: [PATCH 1/2] [libc++] LWG 3821 uses_allocator_construction_args should
have overload for pair-like
---
libcxx/docs/Status/Cxx23Issues.csv | 2 +-
.../__memory/uses_allocator_construction.h | 62 ++++++++++++++-----
libcxx/include/__utility/pair.h | 3 +-
libcxx/include/memory | 37 +++++++++++
.../uses_allocator_construction_args.pass.cpp | 38 ++++++++++--
5 files changed, 119 insertions(+), 23 deletions(-)
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 20b0fa7fc9d1fcd..805cb55768d6c21 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -262,7 +262,7 @@
"`3742 <https://wg21.link/LWG3742>`__","``deque::prepend_range`` needs to permute","February 2023","","","|ranges|"
"`3790 <https://wg21.link/LWG3790>`__","`P1467 <https://wg21.link/P1467>`__ accidentally changed ``nexttoward``'s signature","February 2023","","",""
"`3819 <https://wg21.link/LWG3819>`__","``reference_meows_from_temporary`` should not use ``is_meowible``","February 2023","","",""
-"`3821 <https://wg21.link/LWG3821>`__","``uses_allocator_construction_args`` should have overload for ``pair-like``","February 2023","","",""
+"`3821 <https://wg21.link/LWG3821>`__","``uses_allocator_construction_args`` should have overload for ``pair-like``","February 2023","|Complete|","18.0.0",""
"`3834 <https://wg21.link/LWG3834>`__","Missing ``constexpr`` for ``std::intmax_t`` math functions in ``<cinttypes>``","February 2023","","",""
"`3839 <https://wg21.link/LWG3839>`__","``range_formatter``'s ``set_separator``, ``set_brackets``, and ``underlying`` functions should be ``noexcept``","February 2023","|Complete|","17.0","|format|"
"`3841 <https://wg21.link/LWG3841>`__","``<version>`` should not be ""all freestanding""","February 2023","","",""
diff --git a/libcxx/include/__memory/uses_allocator_construction.h b/libcxx/include/__memory/uses_allocator_construction.h
index a2e4f6e26f4b3af..e4ac89e60379c80 100644
--- a/libcxx/include/__memory/uses_allocator_construction.h
+++ b/libcxx/include/__memory/uses_allocator_construction.h
@@ -12,6 +12,7 @@
#include <__config>
#include <__memory/construct_at.h>
#include <__memory/uses_allocator.h>
+#include <__tuple/pair_like.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_same.h>
#include <__type_traits/remove_cv.h>
@@ -36,7 +37,10 @@ inline constexpr bool __is_std_pair = false;
template <class _Type1, class _Type2>
inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
-template <class _Type, class _Alloc, class... _Args, __enable_if_t<!__is_std_pair<_Type>, int> = 0>
+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<_Type, _Alloc> && is_constructible_v<_Type, _Args...>) {
@@ -52,7 +56,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noe
}
}
-template <class _Pair, class _Alloc, class _Tuple1, class _Tuple2, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
+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(
@@ -71,12 +75,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(
std::forward<_Tuple2>(__y)));
}
-template <class _Pair, class _Alloc, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
+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_std_pair<_Pair>, int> = 0>
+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>(
@@ -87,7 +91,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v)
}
# if _LIBCPP_STD_VER >= 23
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
+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>(
@@ -95,14 +99,14 @@ __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair
}
# endif
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
+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_std_pair<_Pair>, int> = 0>
+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>(
@@ -113,7 +117,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pai
}
# if _LIBCPP_STD_VER >= 23
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
+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>(
@@ -122,6 +126,20 @@ __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&&
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 _PairLike,
+ __enable_if_t<__is_cv_std_pair<_Pair> && !__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value,
+ 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
namespace __uses_allocator_detail {
@@ -139,23 +157,33 @@ template <class _Tp>
inline constexpr bool __convertible_to_const_pair_ref =
decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl<_Tp>(0))::value;
+# if _LIBCPP_STD_VER >= 23
+template <class _Tp, class _Up>
+inline constexpr bool __uses_allocator_constraints =
+ __is_cv_std_pair<_Tp> &&
+ (__is_specialization_of_subrange<remove_cvref_t<_Up>>::value ||
+ (!__pair_like<_Up> && !__convertible_to_const_pair_ref<_Up>));
+# else
+template <class _Tp, class _Up>
+inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !__convertible_to_const_pair_ref<_Up>;
+# endif
+
} // namespace __uses_allocator_detail
-template <
- class _Pair,
- class _Alloc,
- class _Type,
- __enable_if_t<__is_std_pair<_Pair> && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int> = 0>
+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<__is_std_pair<_Pair> && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int>>
+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 {
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 62dac6dd1da3f02..535344eb1e2d63f 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -284,7 +284,8 @@ struct _LIBCPP_TEMPLATE_VIS pair
}
template <__pair_like _PairLike>
- requires(is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike&&>()))> &&
+ requires(!__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value &&
+ is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike&&>()))> &&
is_constructible_v<second_type, decltype(std::get<1>(std::declval<_PairLike&&>()))>)
_LIBCPP_HIDE_FROM_ABI constexpr explicit(__pair_like_explicit_wknd<_PairLike>())
pair(_PairLike&& __p)
diff --git a/libcxx/include/memory b/libcxx/include/memory
index cd6bcc7eaa35d76..f8f7a62951f15e3 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -867,6 +867,43 @@ template <class T> struct hash<shared_ptr<T> >;
template <class T, class Alloc>
inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value;
+// [allocator.uses.construction], uses-allocator construction
+template<class T, class Alloc, class... Args>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ Args&&... args) noexcept;
+template<class T, class Alloc, class Tuple1, class Tuple2>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ piecewise_construct_t,
+ Tuple1&& x, Tuple2&& y) noexcept;
+template<class T, class Alloc>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; // freestanding, since C++20
+template<class T, class Alloc, class U, class V>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ U&& u, V&& v) noexcept;
+template<class T, class Alloc, class U, class V>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++23
+ pair<U, V>& pr) noexcept;
+template<class T, class Alloc, class U, class V>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ const pair<U, V>& pr) noexcept;
+template<class T, class Alloc, class U, class V>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ pair<U, V>&& pr) noexcept;
+template<class T, class Alloc, class U, class V>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++23
+ const pair<U, V>&& pr) noexcept;
+template<class T, class Alloc, pair-like P>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ P&& p) noexcept;
+template<class T, class Alloc, class U>
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ U&& u) noexcept;
+template<class T, class Alloc, class... Args>
+ constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); // freestanding, since C++20
+template<class T, class Alloc, class... Args>
+ constexpr T* uninitialized_construct_using_allocator(T* p, // freestanding, since C++20
+ const Alloc& alloc, Args&&... args);
+
// [ptr.align]
void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp
index 739278e74ddab4f..0ad5e12e8e1c115 100644
--- a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp
+++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp
@@ -16,6 +16,7 @@
#include <concepts>
#include <memory>
+#include <ranges>
#include <tuple>
#include <utility>
@@ -132,19 +133,48 @@ constexpr bool test() {
}
#endif
{
- ConvertibleToPair ctp {};
- auto ret = test_uses_allocator_construction_args<std::pair<int, int>>(a, ctp);
+ ConvertibleToPair ctp{};
+ auto ret = test_uses_allocator_construction_args<std::pair<int, int>>(a, ctp);
std::pair<int, int> v = std::get<0>(ret);
assert(std::get<0>(v) == 1);
assert(std::get<1>(v) == 2);
}
{
- ConvertibleToPair ctp {};
- auto ret = test_uses_allocator_construction_args<std::pair<int, int>>(a, std::move(ctp));
+ ConvertibleToPair ctp{};
+ auto ret = test_uses_allocator_construction_args<std::pair<int, int>>(a, std::move(ctp));
std::pair<int, int> v = std::get<0>(ret);
assert(std::get<0>(v) == 1);
assert(std::get<1>(v) == 2);
}
+#if TEST_STD_VER >= 23
+ // LWG 3821
+ // uses_allocator_construction_args should have overload for pair-like
+ {
+ // pair-like with explicit ctr should work
+ struct Foo {
+ int i = 5;
+ };
+ struct Bar {
+ int i;
+ constexpr explicit Bar(Foo foo) : i(foo.i) {}
+ };
+
+ std::tuple<Foo, Foo> pair_like;
+ auto ret = test_uses_allocator_construction_args<std::pair<Bar, Bar>>(a, pair_like);
+ auto pair = std::make_from_tuple<std::pair<Bar, Bar>>(std::move(ret));
+ assert(pair.first.i == 5);
+ assert(pair.second.i == 5);
+ }
+ {
+ // subrange should work
+ int i = 5;
+ std::ranges::subrange<int*, int*> r{&i, &i};
+ auto ret = std::__uses_allocator_construction_args<std::pair<int*, int*>>(a, r);
+ auto pair = std::make_from_tuple<std::pair<int*, int*>>(std::move(ret));
+ assert(pair.first == &i);
+ assert(pair.second == &i);
+ }
+#endif
return true;
}
>From 847e133057a9df5d22d8f9540e7657485e6a72ad Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Thu, 21 Sep 2023 22:32:28 +0100
Subject: [PATCH 2/2] remove freestanding
---
libcxx/include/memory | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/libcxx/include/memory b/libcxx/include/memory
index f8f7a62951f15e3..24ba82f43ddd309 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -869,39 +869,39 @@ template <class T, class Alloc>
// [allocator.uses.construction], uses-allocator construction
template<class T, class Alloc, class... Args>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
Args&&... args) noexcept;
template<class T, class Alloc, class Tuple1, class Tuple2>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
piecewise_construct_t,
Tuple1&& x, Tuple2&& y) noexcept;
template<class T, class Alloc>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; // since C++20
template<class T, class Alloc, class U, class V>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
U&& u, V&& v) noexcept;
template<class T, class Alloc, class U, class V>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++23
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++23
pair<U, V>& pr) noexcept;
template<class T, class Alloc, class U, class V>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
const pair<U, V>& pr) noexcept;
template<class T, class Alloc, class U, class V>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
pair<U, V>&& pr) noexcept;
template<class T, class Alloc, class U, class V>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++23
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++23
const pair<U, V>&& pr) noexcept;
template<class T, class Alloc, pair-like P>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
P&& p) noexcept;
template<class T, class Alloc, class U>
- constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding, since C++20
+ constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20
U&& u) noexcept;
template<class T, class Alloc, class... Args>
- constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); // freestanding, since C++20
+ constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); // since C++20
template<class T, class Alloc, class... Args>
- constexpr T* uninitialized_construct_using_allocator(T* p, // freestanding, since C++20
+ constexpr T* uninitialized_construct_using_allocator(T* p, // since C++20
const Alloc& alloc, Args&&... args);
// [ptr.align]
More information about the libcxx-commits
mailing list