[libcxx-commits] [libcxx] [libc++] P2255R2: Add deleted `pair` constructor overloads (PR #164214)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Oct 20 03:20:23 PDT 2025
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/164214
>From 9d88b1741ba5f5a3b413f247174a791ea8f26d33 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 20 Oct 2025 15:56:24 +0800
Subject: [PATCH] [libc++] P2255R2: Add deleted `pair` constructor overloads
Implements parts for `std::pair` from P2255R2 "A type trait to detect
reference binding to temporary".
---
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/include/__utility/pair.h | 77 +++++-
.../flat.map/flat.map.observers/comp.pass.cpp | 2 +-
.../flat.multimap.observers/comp.pass.cpp | 2 +-
.../pairs/pairs.pair/ctor.U_V.pass.cpp | 12 +-
.../pairs/pairs.pair/ctor.deleted.verify.cpp | 229 ++++++++++++++++++
.../ctor.pair_U_V_const_move.pass.cpp | 8 +
.../ctor.pair_U_V_const_ref.pass.cpp | 13 +-
.../pairs.pair/ctor.pair_U_V_move.pass.cpp | 10 +
.../pairs.pair/ctor.pair_U_V_ref.pass.cpp | 8 +
.../pairs/pairs.pair/ctor.pair_like.pass.cpp | 46 ++++
11 files changed, 396 insertions(+), 13 deletions(-)
create mode 100644 libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 3a87e64339e1f..030f85e1315ab 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -43,7 +43,7 @@
"`P0627R6 <https://wg21.link/P0627R6>`__","Function to mark unreachable code","2022-02 (Virtual)","|Complete|","15","`#105175 <https://github.com/llvm/llvm-project/issues/105175>`__",""
"`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>`__",""
"`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."
-"`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."
+"`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."
"`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","`#105182 <https://github.com/llvm/llvm-project/issues/105182>`__",""
"`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>`__",""
"`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."
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 33694c52430f1..335757e378841 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -16,6 +16,7 @@
#include <__config>
#include <__cstddef/size_t.h>
#include <__fwd/array.h>
+#include <__fwd/complex.h>
#include <__fwd/pair.h>
#include <__fwd/tuple.h>
#include <__tuple/tuple_like_no_subrange.h>
@@ -36,6 +37,7 @@
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/nat.h>
+#include <__type_traits/reference_constructs_from_temporary.h>
#include <__type_traits/unwrap_ref.h>
#include <__utility/declval.h>
#include <__utility/forward.h>
@@ -68,9 +70,23 @@ struct __check_pair_construction {
template <class _U1, class _U2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() {
+# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
+ !reference_constructs_from_temporary_v<_T1, _U1&&> && !reference_constructs_from_temporary_v<_T2, _U2&&>;
+# else
return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
+# endif
}
+# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ template <class _U1, class _U2>
+ static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructor_deleted() {
+ return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
+ (reference_constructs_from_temporary_v<_T1, _U1&&> || reference_constructs_from_temporary_v<_T2, _U2&&>);
+ return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
+ }
+# endif
+
template <class _U1, class _U2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() {
return is_convertible<_U1, _T1>::value && is_convertible<_U2, _T2>::value;
@@ -157,14 +173,20 @@ struct pair
class _U1,
class _U2,
# endif
- __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0 >
+ __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0 >
_LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
pair(_U1&& __u1, _U2&& __u2) noexcept(is_nothrow_constructible<first_type, _U1>::value &&
is_nothrow_constructible<second_type, _U2>::value)
: first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
}
+# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ template <class _U1 = _T1, class _U2 = _T2>
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
+ explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>()) pair(_U1&&, _U2&&) = delete;
+# endif
+
# if _LIBCPP_STD_VER >= 23
template <class _U1,
class _U2,
@@ -173,6 +195,12 @@ struct pair
pair(pair<_U1, _U2>& __p) noexcept((is_nothrow_constructible<first_type, _U1&>::value &&
is_nothrow_constructible<second_type, _U2&>::value))
: first(__p.first), second(__p.second) {}
+
+# if __has_builtin(__reference_constructs_from_temporary)
+ template <class _U1, class _U2>
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1&, _U2&>())
+ explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>&) = delete;
+# endif
# endif
template <
@@ -186,15 +214,30 @@ struct pair
is_nothrow_constructible<second_type, _U2 const&>::value)
: first(__p.first), second(__p.second) {}
- template <class _U1,
- class _U2,
- __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0>
+# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ template <class _U1, class _U2>
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1&, const _U2&>())
+ explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&, const _U2&>())
+ pair(const pair<_U1, _U2>&) = delete;
+# endif
+
+ template <
+ class _U1,
+ class _U2,
+ __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
pair(pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, _U1&&>::value &&
is_nothrow_constructible<second_type, _U2&&>::value)
: first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {}
+# if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ template <class _U1, class _U2>
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
+ explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
+ pair(pair<_U1, _U2>&&) = delete;
+# endif
+
# if _LIBCPP_STD_VER >= 23
template <
class _U1,
@@ -206,16 +249,34 @@ struct pair
pair(const pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, const _U1&&>::value &&
is_nothrow_constructible<second_type, const _U2&&>::value)
: first(std::move(__p.first)), second(std::move(__p.second)) {}
+
+# if __has_builtin(__reference_constructs_from_temporary)
+ template <class _U1, class _U2>
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1 &&, const _U2 &&>())
+ explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&&, const _U2&&>())
+ pair(const pair<_U1, _U2>&&) = delete;
+# endif
# endif
# if _LIBCPP_STD_VER >= 23
template <__pair_like_no_subrange _PairLike>
- requires(is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike &&>()))> &&
- is_constructible_v<second_type, decltype(std::get<1>(std::declval<_PairLike &&>()))>)
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructible<
+ decltype(std::get<0>(std::declval<_PairLike &&>())),
+ decltype(std::get<1>(std::declval<_PairLike &&>()))>())
_LIBCPP_HIDE_FROM_ABI constexpr explicit(
!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
!is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>) pair(_PairLike&& __p)
: first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {}
+
+# if __has_builtin(__reference_constructs_from_temporary)
+ template <__pair_like_no_subrange _PairLike>
+ requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<
+ decltype(std::get<0>(std::declval<_PairLike &&>())),
+ decltype(std::get<1>(std::declval<_PairLike &&>()))>())
+ explicit(!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
+ !is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>)
+ pair(_PairLike&&) = delete;
+# endif
# endif
template <class... _Args1, class... _Args2>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp
index 5712493740bc8..626f6ad64c635 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp
@@ -35,7 +35,7 @@ constexpr bool test() {
assert(kc(1, 2));
assert(!kc(2, 1));
auto vc = m.value_comp();
- ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, 2), std::make_pair(1, 2))), bool);
+ ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, '2'), std::make_pair(1, '2'))), bool);
assert(vc({1, '2'}, {2, '1'}));
assert(!vc({2, '1'}, {1, '2'}));
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
index 070fbb0244e63..2b52b4722f347 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
@@ -36,7 +36,7 @@ constexpr bool test() {
assert(kc(1, 2));
assert(!kc(2, 1));
auto vc = m.value_comp();
- ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, 2), std::make_pair(1, 2))), bool);
+ ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, '2'), std::make_pair(1, '2'))), bool);
assert(vc({1, '2'}, {2, '1'}));
assert(!vc({2, '1'}, {1, '2'}));
}
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp
index 33b5711e22183..63b254d102041 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp
@@ -139,5 +139,15 @@ int main(int, char**)
}
#endif // TEST_STD_VER > 20
- return 0;
+// Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ test_sfinae<int&&, char, false>();
+ test_sfinae<const int&, char, false>();
+ test_sfinae<ConvertingType&&, int, false>();
+ test_sfinae<const ConvertingType&, char, false>();
+ test_sfinae<ExplicitTypes::ConvertingType&&, int, false>();
+ test_sfinae<const ExplicitTypes::ConvertingType&, int, false>();
+#endif // TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+
+ return 0;
}
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp
new file mode 100644
index 0000000000000..12e2c5674bc56
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp
@@ -0,0 +1,229 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++11
+
+// <utility>
+
+// template <class T1, class T2> struct pair
+
+// template<class U1 = T1, class U2 = T2>
+// constexpr explicit(see below) pair(U1&& x, U2&& y); // since C++11
+
+// The constructor is defined as deleted if
+// reference_constructs_from_temporary_v<first_type, U1&&> || reference_constructs_from_temporary_v<second_type, U2>
+// is true. (since C++23)
+
+// template<class U1, class U2>
+// constexpr explicit(see below) pair(pair<U1, U2>& p); // since C++23
+// template<class U1, class U2>
+// constexpr explicit(see below) pair(const pair<U1, U2>& p); // since C++11
+// template<class U1, class U2>
+// constexpr explicit(see below) pair(pair<U1, U2>&& p); // since C++11
+// template<class U1, class U2>
+// constexpr explicit(see below) pair(const pair<U1, U2>&& p); // since C++23
+// template<pair-like P>
+// constexpr explicit(see below) pair(P&& p); // since C++23
+
+// The constructor is defined as deleted if
+// reference_constructs_from_temporary_v<first_type, decltype(get<0>(FWD(p)))> ||
+// reference_constructs_from_temporary_v<second_type, decltype(get<1>(FWD(p)))>
+// is true. (since C++23)
+
+// Such reference binding used to cause hard error for these constructors before C++23 due to CWG1696.
+
+#include <array>
+#include <complex>
+#include <tuple>
+#include <utility>
+
+#include "test_macros.h"
+
+void verify_two_arguments() {
+ std::pair<const long&, int&&> p1{'a', 'b'};
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+
+#if TEST_STD_VER >= 23
+ std::pair<const long, int&&> p2({42L}, 'c');
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{call to deleted constructor of 'std::pair<const long, int &&>'}}
+# else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ std::pair<const long&, int> p3{'d', {}};
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{call to deleted constructor of 'std::pair<const long &, int>'}}
+# else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+#endif
+}
+
+void verify_pair_const_lvalue() {
+ const std::pair<char, int> src1{'a', 'b'};
+ std::pair<const long&, const int&> dst1 = src1;
+ (void)dst1;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -3 {{invokes a deleted function}}
+#else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+
+ const std::pair<long, char> src2{'a', 'b'};
+ std::pair<const long&, const int&> dst2 = src2;
+ (void)dst2;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -3 {{conversion function from 'const pair<long, char>' to 'pair<const long &, const int &>' invokes a deleted function}}
+#else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+}
+
+void verify_pair_rvalue() {
+ std::pair<char, int> src1{'a', 'b'};
+ std::pair<const long&, int&&> dst1 = std::move(src1);
+ (void)dst1;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -3 {{invokes a deleted function}}
+#else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+
+ std::pair<long, char> src2{'a', 'b'};
+ std::pair<const long&, int&&> dst2 = std::move(src2);
+ (void)dst2;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -3 {{invokes a deleted function}}
+#else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+}
+
+#if TEST_STD_VER >= 23
+void verify_pair_lvalue() {
+ std::pair<char, int> src1{'a', 'b'};
+ std::pair<const long&, int&> dst1 = src1;
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ std::pair<long, char> src2{'a', 'b'};
+ std::pair<const long&, int&&> dst2 = src2;
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+}
+
+void verify_pair_const_rvalue() {
+ const std::pair<char, int> src1{'a', 'b'};
+ std::pair<const long&, const int&&> dst1 = std::move(src1);
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ const std::pair<long, char> src2{'a', 'b'};
+ std::pair<const long&, const int&&> dst2 = std::move(src2);
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+}
+
+void verify_pair_like() {
+ std::pair<const long&, int&&> p1 = std::make_tuple('a', int{'b'});
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ std::pair<const long&, int&&> p2 = std::make_tuple(long{'a'}, 'b');
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ std::pair<const char&, int&&> p3 = std::array<char, 2>{'a', 'b'};
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ std::pair<const long&, char&&> p4 = std::array<char, 2>{'a', 'b'};
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+# if TEST_STD_VER >= 26
+ std::pair<const long double&, float&&> p5 = std::complex<float>{42.0f, 1729.0f};
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+
+ std::pair<const float&, double&&> p6 = std::complex<float>{3.14159f, 2.71828f};
+# if __has_builtin(__reference_constructs_from_temporary)
+ // expected-error at -2 {{invokes a deleted function}}
+# else
+ // expected-error@*:* {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+# endif
+# endif
+}
+#endif
+
+// Verify that copy-non-list-initialization ignores explicit but deleted overloads.
+void verify_explicity() {
+ struct ExplicitlyToInt {
+ explicit operator int() const;
+ };
+
+ const std::pair<int, ExplicitlyToInt> src1;
+ std::pair<int, int&&> dst1 = src1; // expected-error {{no viable conversion}}
+
+ std::pair<int, ExplicitlyToInt> src2;
+ std::pair<int, int&&> dst2 = std::move(src2); // expected-error {{no viable conversion}}
+
+#if TEST_STD_VER >= 23
+ const std::pair<int, ExplicitlyToInt> src3;
+ std::pair<int, int&&> dst3 = std::move(src3); // expected-error {{no viable conversion}}
+
+ std::pair<int, ExplicitlyToInt> src4;
+ std::pair<int, int&&> dst4 = src4; // expected-error {{no viable conversion}}
+
+ std::pair<int, int&&> dst5 = std::make_tuple(0, ExplicitlyToInt{}); // expected-error {{no viable conversion}}
+
+ std::pair<int&&, int> dst6 = std::array<ExplicitlyToInt, 2>{}; // expected-error {{no viable conversion}}
+#endif
+
+#if TEST_STD_VER >= 26
+ struct ExplicitlyFromFloat {
+ explicit ExplicitlyFromFloat(float);
+ };
+
+ std::pair<ExplicitlyFromFloat, const ExplicitlyFromFloat&> dst7 = // expected-error {{no viable conversion}}
+ std::complex<float>{};
+#endif
+}
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_move.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_move.pass.cpp
index 63f409b332878..89eb6ab9dcea2 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_move.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_move.pass.cpp
@@ -47,6 +47,14 @@ static_assert(!std::is_convertible_v<const std::pair<X, Y>&&,
std::pair<ExplicitConstructibleFrom<X>, ExplicitConstructibleFrom<Y>>>);
// clang-format on
+// Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if __has_builtin(__reference_constructs_from_temporary)
+static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, const std::pair<int, short>&&>);
+static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, const std::pair<char, long>&&>);
+static_assert(!std::is_convertible_v<const std::pair<int, short>&&, std::pair<const int&, const long&>>);
+static_assert(!std::is_convertible_v<const std::pair<char, long>&&, std::pair<const int&, const long&>>);
+#endif // __has_builtin(__reference_constructs_from_temporary)
+
constexpr bool test() {
// simple case: init pair<const T&&, const U&&> from const pair<T, U>&&
{
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_ref.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_ref.pass.cpp
index 3a1e9ad08fb14..25ccc14428474 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_ref.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_ref.pass.cpp
@@ -189,7 +189,18 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(p2.second.value == 101, "");
}
#endif
- return true;
+
+// Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ test_pair_const<int&&, char, false>();
+ test_pair_const<const int&, char, false>();
+ test_pair_const<ConvertingType&&, int, false>();
+ test_pair_const<const ConvertingType&, char, false>();
+ test_pair_const<ExplicitTypes::ConvertingType&&, int, false>();
+ test_pair_const<const ExplicitTypes::ConvertingType&, int, false>();
+#endif // TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+
+ return true;
}
int main(int, char**) {
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_move.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_move.pass.cpp
index 8ba9b5696eff1..ad144b0b8cac7 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_move.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_move.pass.cpp
@@ -244,5 +244,15 @@ int main(int, char**)
}
#endif
+// Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ test_pair_rv<int&&, char, false>();
+ test_pair_rv<const int&, char, false>();
+ test_pair_rv<ConvertingType&&, int, false>();
+ test_pair_rv<const ConvertingType&, char, false>();
+ test_pair_rv<ExplicitTypes::ConvertingType&&, int, false>();
+ test_pair_rv<const ExplicitTypes::ConvertingType&, int, false>();
+#endif // TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+
return 0;
}
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_ref.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_ref.pass.cpp
index 7ac70bf36a780..42d338b756917 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_ref.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_ref.pass.cpp
@@ -42,6 +42,14 @@ static_assert(!std::is_convertible_v<std::pair<X, Y>&, std::pair<ExplicitConstru
static_assert(!std::is_convertible_v<std::pair<X, Y>&, std::pair<ExplicitConstructibleFrom<X>, ExplicitConstructibleFrom<Y>>>);
// clang-format on
+// Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if __has_builtin(__reference_constructs_from_temporary)
+static_assert(!std::is_constructible_v<std::pair<const int&, long&&>, std::pair<const char, const long>&>);
+static_assert(!std::is_constructible_v<std::pair<const short&, long&&>, std::pair<const short, const char>&>);
+static_assert(!std::is_convertible_v<std::pair<const char, const long>&, std::pair<const int&, long&&>>);
+static_assert(!std::is_convertible_v<std::pair<const short, const char>&, std::pair<const short&, long&&>>);
+#endif // __has_builtin(__reference_constructs_from_temporary)
+
constexpr bool test() {
// use case in zip. Init pair<T&, U&> from pair<T, U>&
{
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_like.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_like.pass.cpp
index 135045d831d90..1ddfa5d03c810 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_like.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_like.pass.cpp
@@ -17,12 +17,15 @@
#include <array>
#include <cassert>
+#include <complex>
#include <ranges>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
+#include "test_macros.h"
+
namespace my_ns{
struct MyPairLike {
@@ -138,6 +141,49 @@ constexpr bool test() {
static_assert(!std::is_convertible_v<std::tuple<FromExplicit, FromExplicit>, std::pair<To, To>>);
}
}
+
+ // Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if __has_builtin(__reference_constructs_from_temporary)
+ // Test tuple.
+ {
+ static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, std::tuple<char, long>>);
+ static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, const std::tuple<char, long>&>);
+ static_assert(!std::is_convertible_v<std::tuple<char, long>, std::pair<const int&, const long&>>);
+ static_assert(!std::is_convertible_v<const std::tuple<char, long>&, std::pair<const int&, const long&>>);
+
+ static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, std::tuple<int, short>>);
+ static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, const std::tuple<int, short>&>);
+ static_assert(!std::is_convertible_v<std::tuple<int, short>, std::pair<const int&, const long&>>);
+ static_assert(!std::is_convertible_v<const std::tuple<char, short>&, std::pair<const int&, const long&>>);
+ }
+ // Test array.
+ {
+ static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, std::array<int, 2>>);
+ static_assert(!std::is_constructible_v<std::pair<const long&, const int&>, std::array<int, 2>>);
+ static_assert(!std::is_constructible_v<std::pair<const int&, const long&>, const std::array<int, 2>&>);
+ static_assert(!std::is_constructible_v<std::pair<const long&, const int&>, const std::array<int, 2>&>);
+
+ static_assert(!std::is_convertible_v<std::array<int, 2>, std::pair<const int&, const long&>>);
+ static_assert(!std::is_convertible_v<std::array<int, 2>, std::pair<const long&, const int&>>);
+ static_assert(!std::is_convertible_v<const std::array<int, 2>&, std::pair<const int&, const long&>>);
+ static_assert(!std::is_convertible_v<const std::array<int, 2>&, std::pair<const long&, const int&>>);
+ }
+# if TEST_STD_VER >= 26
+ // Test complex.
+ {
+ static_assert(!std::is_constructible_v<std::pair<const double&, const float&>, std::complex<float>>);
+ static_assert(!std::is_constructible_v<std::pair<const float&, const double&>, std::complex<float>>);
+ static_assert(!std::is_convertible_v<std::complex<float>, std::pair<const double&, const float&>>);
+ static_assert(!std::is_convertible_v<std::complex<float>, std::pair<const float&, const double&>>);
+
+ static_assert(!std::is_constructible_v<std::pair<const double&, const long double&>, const std::complex<double>&>);
+ static_assert(!std::is_constructible_v<std::pair<const long double&, const double&>, const std::complex<double>&>);
+ static_assert(!std::is_convertible_v<const std::complex<double>&, std::pair<const double&, const long double&>>);
+ static_assert(!std::is_convertible_v<const std::complex<double>&, std::pair<const long double&, const double&>>);
+ }
+# endif // TEST_STD_VER >= 26
+#endif // __has_builtin(__reference_constructs_from_temporary)
+
return true;
}
More information about the libcxx-commits
mailing list