Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
71 changes: 63 additions & 8 deletions libcxx/include/__utility/pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -68,8 +70,22 @@ struct __check_pair_construction {

template <class _U1, class _U2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() {
# if _LIBCPP_STD_VER >= 23
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
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() {
Expand Down Expand Up @@ -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
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,
Expand All @@ -173,6 +195,10 @@ 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) {}

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

template <
Expand All @@ -186,15 +212,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
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
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,
Expand All @@ -206,16 +247,30 @@ 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)) {}

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

# 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))) {}

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

template <class... _Args1, class... _Args2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'}));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'}));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
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

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//===----------------------------------------------------------------------===//
//
// 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
// expected-error@-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');
// expected-error@-1 {{call to deleted constructor of 'std::pair<const long, int &&>'}}
std::pair<const long&, int> p3{'d', {}};
// expected-error@-1 {{call to deleted constructor of 'std::pair<const long &, int>'}}
#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
// expected-error@-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
// expected-error@-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
// expected-error@-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
// expected-error@-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; // expected-error {{invokes a deleted function}}

std::pair<long, char> src2{'a', 'b'};
std::pair<const long&, int&&> dst2 = src2; // expected-error {{invokes a deleted function}}
}

void verify_pair_const_rvalue() {
const std::pair<char, int> src1{'a', 'b'};
std::pair<const long&, const int&&> dst1 = std::move(src1); // expected-error {{invokes a deleted function}}

const std::pair<long, char> src2{'a', 'b'};
std::pair<const long&, const int&&> dst2 = std::move(src2); // expected-error {{invokes a deleted function}}
}

void verify_pair_like() {
std::pair<const long&, int&&> p1 = std::make_tuple('a', int{'b'}); // expected-error {{invokes a deleted function}}
std::pair<const long&, int&&> p2 = std::make_tuple(long{'a'}, 'b'); // expected-error {{invokes a deleted function}}
std::pair<const char&, int&&> p3 = std::array<char, 2>{'a', 'b'}; // expected-error {{invokes a deleted function}}
std::pair<const long&, char&&> p4 = std::array<char, 2>{'a', 'b'}; // expected-error {{invokes a deleted function}}

# if TEST_STD_VER >= 26
std::pair<const long double&, float&&> p5 = std::complex<float>{42.0f, 1729.0f};
// expected-error@-1 {{invokes a deleted function}}
std::pair<const float&, double&&> p6 = std::complex<float>{3.14159f, 2.71828f};
// expected-error@-1 {{invokes a deleted function}}
# 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
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ 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.
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&>>);

constexpr bool test() {
// simple case: init pair<const T&&, const U&&> from const pair<T, U>&&
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
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

return true;
}

int main(int, char**) {
Expand Down
Loading
Loading