-
Couldn't load subscription status.
- Fork 15k
[libc++] P2255R2: Add deleted pair constructor overloads
#164214
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
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-libcxx Author: A. Jiang (frederick-vs-ja) ChangesImplements parts for Fixes #129051. Patch is 31.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/164214.diff 11 Files Affected:
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..7ab475a49ab38 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -36,6 +36,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 +69,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 +172,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 +194,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 +213,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 +248,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..0b1bfc097965b
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp
@@ -0,0 +1,225 @@
+//===----------------------------------------------------------------------===//
+//
+// 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@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+ // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+ // expected-error@-5 {{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@-2 {{call to deleted constructor of 'std::pair<const long, int &&>'}}
+# else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, int>'}}
+# else
+ // expected-error@-4 {{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;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &>'}}
+#else
+ // expected-error@-4 {{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;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &>'}}
+#else
+ // expected-error@-4 {{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);
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+ // expected-error@-4 {{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);
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+ // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, int &>'}}
+# else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+# else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, const int &&>'}}
+# else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, const int &&>'}}
+# else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, const int &&>'}}
+# else
+ // expected-error@-4 {{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@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+# else
...
[truncated]
|
8e3073b to
0e5e36c
Compare
| #include <__config> | ||
| #include <__cstddef/size_t.h> | ||
| #include <__fwd/array.h> | ||
| #include <__fwd/complex.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems necessary for Clang module builds to find the std::get overloads for complex (added in C++26), which interacts with the constructors from pair-like types.
0e5e36c to
cf41747
Compare
Implements parts for `std::pair` from P2255R2 "A type trait to detect reference binding to temporary".
cf41747 to
9d88b17
Compare
Implements parts for
std::pairfrom P2255R2 "A type trait to detect reference binding to temporary".Fixes #129051.