Skip to content

Commit bf9481d

Browse files
[libc++] P2255R2: Add deleted pair constructor overloads
Implements parts for `std::pair` from P2255R2 "A type trait to detect reference binding to temporary".
1 parent 4d6f43d commit bf9481d

File tree

11 files changed

+391
-13
lines changed

11 files changed

+391
-13
lines changed

libcxx/docs/Status/Cxx23Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"`P0627R6 <https://wg21.link/P0627R6>`__","Function to mark unreachable code","2022-02 (Virtual)","|Complete|","15","`#105175 <https://github.com/llvm/llvm-project/issues/105175>`__",""
4444
"`P1206R7 <https://wg21.link/P1206R7>`__","``ranges::to``: A function to convert any range to a container","2022-02 (Virtual)","|Complete|","17","`#105176 <https://github.com/llvm/llvm-project/issues/105176>`__",""
4545
"`P1413R3 <https://wg21.link/P1413R3>`__","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","2022-02 (Virtual)","|Complete|","","`#105177 <https://github.com/llvm/llvm-project/issues/105177>`__","``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but clang doesn't issue a diagnostic for deprecated using template declarations."
46-
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","`#105180 <https://github.com/llvm/llvm-project/issues/105180>`__","Implemented the type traits only."
46+
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","`#105180 <https://github.com/llvm/llvm-project/issues/105180>`__","Implemented the type traits and changes to ``std::pair`` only."
4747
"`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","`#105182 <https://github.com/llvm/llvm-project/issues/105182>`__",""
4848
"`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 <https://github.com/llvm/llvm-project/issues/105183>`__",""
4949
"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__","Only ``ranges::iota`` is implemented."

libcxx/include/__utility/pair.h

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <__type_traits/is_swappable.h>
3737
#include <__type_traits/is_trivially_relocatable.h>
3838
#include <__type_traits/nat.h>
39+
#include <__type_traits/reference_constructs_from_temporary.h>
3940
#include <__type_traits/unwrap_ref.h>
4041
#include <__utility/declval.h>
4142
#include <__utility/forward.h>
@@ -68,9 +69,23 @@ struct __check_pair_construction {
6869

6970
template <class _U1, class _U2>
7071
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() {
72+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
73+
return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
74+
!reference_constructs_from_temporary_v<_T1, _U1&&> && !reference_constructs_from_temporary_v<_T2, _U2&&>;
75+
# else
7176
return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
77+
# endif
7278
}
7379

80+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
81+
template <class _U1, class _U2>
82+
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructor_deleted() {
83+
return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
84+
(reference_constructs_from_temporary_v<_T1, _U1&&> || reference_constructs_from_temporary_v<_T2, _U2&&>);
85+
return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
86+
}
87+
# endif
88+
7489
template <class _U1, class _U2>
7590
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() {
7691
return is_convertible<_U1, _T1>::value && is_convertible<_U2, _T2>::value;
@@ -157,14 +172,20 @@ struct pair
157172
class _U1,
158173
class _U2,
159174
# endif
160-
__enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0 >
175+
__enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0 >
161176
_LIBCPP_HIDE_FROM_ABI
162-
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
177+
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
163178
pair(_U1&& __u1, _U2&& __u2) noexcept(is_nothrow_constructible<first_type, _U1>::value &&
164179
is_nothrow_constructible<second_type, _U2>::value)
165180
: first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
166181
}
167182

183+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
184+
template <class _U1 = _T1, class _U2 = _T2>
185+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
186+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>()) pair(_U1&&, _U2&&) = delete;
187+
# endif
188+
168189
# if _LIBCPP_STD_VER >= 23
169190
template <class _U1,
170191
class _U2,
@@ -173,6 +194,12 @@ struct pair
173194
pair(pair<_U1, _U2>& __p) noexcept((is_nothrow_constructible<first_type, _U1&>::value &&
174195
is_nothrow_constructible<second_type, _U2&>::value))
175196
: first(__p.first), second(__p.second) {}
197+
198+
# if __has_builtin(__reference_constructs_from_temporary)
199+
template <class _U1, class _U2>
200+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1&, _U2&>())
201+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>&) = delete;
202+
# endif
176203
# endif
177204

178205
template <
@@ -186,15 +213,30 @@ struct pair
186213
is_nothrow_constructible<second_type, _U2 const&>::value)
187214
: first(__p.first), second(__p.second) {}
188215

189-
template <class _U1,
190-
class _U2,
191-
__enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0>
216+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
217+
template <class _U1, class _U2>
218+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1&, const _U2&>())
219+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&, const _U2&>())
220+
pair(const pair<_U1, _U2>&) = delete;
221+
# endif
222+
223+
template <
224+
class _U1,
225+
class _U2,
226+
__enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0>
192227
_LIBCPP_HIDE_FROM_ABI
193-
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
228+
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
194229
pair(pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, _U1&&>::value &&
195230
is_nothrow_constructible<second_type, _U2&&>::value)
196231
: first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {}
197232

233+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
234+
template <class _U1, class _U2>
235+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
236+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
237+
pair(pair<_U1, _U2>&&) = delete;
238+
# endif
239+
198240
# if _LIBCPP_STD_VER >= 23
199241
template <
200242
class _U1,
@@ -206,16 +248,34 @@ struct pair
206248
pair(const pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, const _U1&&>::value &&
207249
is_nothrow_constructible<second_type, const _U2&&>::value)
208250
: first(std::move(__p.first)), second(std::move(__p.second)) {}
251+
252+
# if __has_builtin(__reference_constructs_from_temporary)
253+
template <class _U1, class _U2>
254+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1 &&, const _U2 &&>())
255+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&&, const _U2&&>())
256+
pair(const pair<_U1, _U2>&&) = delete;
257+
# endif
209258
# endif
210259

211260
# if _LIBCPP_STD_VER >= 23
212261
template <__pair_like_no_subrange _PairLike>
213-
requires(is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike &&>()))> &&
214-
is_constructible_v<second_type, decltype(std::get<1>(std::declval<_PairLike &&>()))>)
262+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructible<
263+
decltype(std::get<0>(std::declval<_PairLike &&>())),
264+
decltype(std::get<1>(std::declval<_PairLike &&>()))>())
215265
_LIBCPP_HIDE_FROM_ABI constexpr explicit(
216266
!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
217267
!is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>) pair(_PairLike&& __p)
218268
: first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {}
269+
270+
# if __has_builtin(__reference_constructs_from_temporary)
271+
template <__pair_like_no_subrange _PairLike>
272+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<
273+
decltype(std::get<0>(std::declval<_PairLike &&>())),
274+
decltype(std::get<1>(std::declval<_PairLike &&>()))>())
275+
explicit(!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
276+
!is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>)
277+
pair(_PairLike&&) = delete;
278+
# endif
219279
# endif
220280

221281
template <class... _Args1, class... _Args2>

libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ constexpr bool test() {
3535
assert(kc(1, 2));
3636
assert(!kc(2, 1));
3737
auto vc = m.value_comp();
38-
ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, 2), std::make_pair(1, 2))), bool);
38+
ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, '2'), std::make_pair(1, '2'))), bool);
3939
assert(vc({1, '2'}, {2, '1'}));
4040
assert(!vc({2, '1'}, {1, '2'}));
4141
}

libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ constexpr bool test() {
3636
assert(kc(1, 2));
3737
assert(!kc(2, 1));
3838
auto vc = m.value_comp();
39-
ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, 2), std::make_pair(1, 2))), bool);
39+
ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, '2'), std::make_pair(1, '2'))), bool);
4040
assert(vc({1, '2'}, {2, '1'}));
4141
assert(!vc({2, '1'}, {1, '2'}));
4242
}

libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,15 @@ int main(int, char**)
139139
}
140140
#endif // TEST_STD_VER > 20
141141

142-
return 0;
142+
// Test construction prohibition of introduced by https://wg21.link/P2255R2.
143+
#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
144+
test_sfinae<int&&, char, false>();
145+
test_sfinae<const int&, char, false>();
146+
test_sfinae<ConvertingType&&, int, false>();
147+
test_sfinae<const ConvertingType&, char, false>();
148+
test_sfinae<ExplicitTypes::ConvertingType&&, int, false>();
149+
test_sfinae<const ExplicitTypes::ConvertingType&, int, false>();
150+
#endif // TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
151+
152+
return 0;
143153
}

0 commit comments

Comments
 (0)