Skip to content

Commit 9d88b17

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 a4dde44 commit 9d88b17

File tree

11 files changed

+396
-13
lines changed

11 files changed

+396
-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: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <__config>
1717
#include <__cstddef/size_t.h>
1818
#include <__fwd/array.h>
19+
#include <__fwd/complex.h>
1920
#include <__fwd/pair.h>
2021
#include <__fwd/tuple.h>
2122
#include <__tuple/tuple_like_no_subrange.h>
@@ -36,6 +37,7 @@
3637
#include <__type_traits/is_swappable.h>
3738
#include <__type_traits/is_trivially_relocatable.h>
3839
#include <__type_traits/nat.h>
40+
#include <__type_traits/reference_constructs_from_temporary.h>
3941
#include <__type_traits/unwrap_ref.h>
4042
#include <__utility/declval.h>
4143
#include <__utility/forward.h>
@@ -68,9 +70,23 @@ struct __check_pair_construction {
6870

6971
template <class _U1, class _U2>
7072
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() {
73+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
74+
return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
75+
!reference_constructs_from_temporary_v<_T1, _U1&&> && !reference_constructs_from_temporary_v<_T2, _U2&&>;
76+
# else
7177
return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
78+
# endif
7279
}
7380

81+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
82+
template <class _U1, class _U2>
83+
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructor_deleted() {
84+
return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
85+
(reference_constructs_from_temporary_v<_T1, _U1&&> || reference_constructs_from_temporary_v<_T2, _U2&&>);
86+
return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
87+
}
88+
# endif
89+
7490
template <class _U1, class _U2>
7591
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() {
7692
return is_convertible<_U1, _T1>::value && is_convertible<_U2, _T2>::value;
@@ -157,14 +173,20 @@ struct pair
157173
class _U1,
158174
class _U2,
159175
# endif
160-
__enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0 >
176+
__enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0 >
161177
_LIBCPP_HIDE_FROM_ABI
162-
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
178+
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
163179
pair(_U1&& __u1, _U2&& __u2) noexcept(is_nothrow_constructible<first_type, _U1>::value &&
164180
is_nothrow_constructible<second_type, _U2>::value)
165181
: first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
166182
}
167183

184+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
185+
template <class _U1 = _T1, class _U2 = _T2>
186+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
187+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>()) pair(_U1&&, _U2&&) = delete;
188+
# endif
189+
168190
# if _LIBCPP_STD_VER >= 23
169191
template <class _U1,
170192
class _U2,
@@ -173,6 +195,12 @@ struct pair
173195
pair(pair<_U1, _U2>& __p) noexcept((is_nothrow_constructible<first_type, _U1&>::value &&
174196
is_nothrow_constructible<second_type, _U2&>::value))
175197
: first(__p.first), second(__p.second) {}
198+
199+
# if __has_builtin(__reference_constructs_from_temporary)
200+
template <class _U1, class _U2>
201+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1&, _U2&>())
202+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>&) = delete;
203+
# endif
176204
# endif
177205

178206
template <
@@ -186,15 +214,30 @@ struct pair
186214
is_nothrow_constructible<second_type, _U2 const&>::value)
187215
: first(__p.first), second(__p.second) {}
188216

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

234+
# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
235+
template <class _U1, class _U2>
236+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
237+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
238+
pair(pair<_U1, _U2>&&) = delete;
239+
# endif
240+
198241
# if _LIBCPP_STD_VER >= 23
199242
template <
200243
class _U1,
@@ -206,16 +249,34 @@ struct pair
206249
pair(const pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, const _U1&&>::value &&
207250
is_nothrow_constructible<second_type, const _U2&&>::value)
208251
: first(std::move(__p.first)), second(std::move(__p.second)) {}
252+
253+
# if __has_builtin(__reference_constructs_from_temporary)
254+
template <class _U1, class _U2>
255+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1 &&, const _U2 &&>())
256+
explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&&, const _U2&&>())
257+
pair(const pair<_U1, _U2>&&) = delete;
258+
# endif
209259
# endif
210260

211261
# if _LIBCPP_STD_VER >= 23
212262
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 &&>()))>)
263+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructible<
264+
decltype(std::get<0>(std::declval<_PairLike &&>())),
265+
decltype(std::get<1>(std::declval<_PairLike &&>()))>())
215266
_LIBCPP_HIDE_FROM_ABI constexpr explicit(
216267
!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
217268
!is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>) pair(_PairLike&& __p)
218269
: first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {}
270+
271+
# if __has_builtin(__reference_constructs_from_temporary)
272+
template <__pair_like_no_subrange _PairLike>
273+
requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<
274+
decltype(std::get<0>(std::declval<_PairLike &&>())),
275+
decltype(std::get<1>(std::declval<_PairLike &&>()))>())
276+
explicit(!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
277+
!is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>)
278+
pair(_PairLike&&) = delete;
279+
# endif
219280
# endif
220281

221282
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)