[libcxx][type_traits] Add C++20 changes to common_type

Summary: This already implements the expected changes for LWG-3205

Reviewers: mclow.lists, EricWF, CaseyCarter, cjdb, #libc, ldionne

Reviewed By: #libc, ldionne

Subscribers: dexonsmith, broadwaylamb, christof, ldionne, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D74350
This commit is contained in:
Michael Schellenberger Costa 2020-05-18 14:01:55 +02:00
parent a675c1dee4
commit c579ab9962
2 changed files with 80 additions and 13 deletions

View File

@ -2348,9 +2348,33 @@ struct _LIBCPP_TEMPLATE_VIS make_unsigned
template <class _Tp> using make_unsigned_t = typename make_unsigned<_Tp>::type;
#endif
#if _LIBCPP_STD_VER > 14
template <class...> using void_t = void;
#endif
#if _LIBCPP_STD_VER > 17
// Let COND_RES(X, Y) be:
template <class _Tp, class _Up>
using __cond_type = decltype(false ? _VSTD::declval<_Tp>() : _VSTD::declval<_Up>());
template <class _Tp, class _Up, class = void>
struct __common_type3 {};
// sub-bullet 4 - "if COND_RES(CREF(D1), CREF(D2)) denotes a type..."
template <class _Tp, class _Up>
struct __common_type3<_Tp, _Up, void_t<__cond_type<const _Tp&, const _Up&>>>
{
using type = remove_cvref_t<__cond_type<const _Tp&, const _Up&>>;
};
template <class _Tp, class _Up, class = void>
struct __common_type2_imp : __common_type3<_Tp, _Up> {};
#else
template <class _Tp, class _Up, class = void>
struct __common_type2_imp {};
#endif
// sub-bullet 3 - "if decay_t<decltype(false ? declval<D1>() : declval<D2>())> ..."
template <class _Tp, class _Up>
struct __common_type2_imp<_Tp, _Up,
typename __void_t<decltype(
@ -2414,6 +2438,7 @@ struct _LIBCPP_TEMPLATE_VIS common_type<_Tp>
// bullet 3 - sizeof...(Tp) == 2
// sub-bullet 1 - "If is_same_v<T1, D1> is false or ..."
template <class _Tp, class _Up>
struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up>
: conditional<
@ -4296,8 +4321,6 @@ struct __has_operator_addressof
#if _LIBCPP_STD_VER > 14
template <class...> using void_t = void;
template <class... _Args>
struct conjunction : _And<_Args...> {};
template<class... _Args>

View File

@ -24,6 +24,13 @@ struct X { explicit X(T const&){} };
template <class T>
struct S { explicit S(T const&){} };
template <class T>
struct bad_reference_wrapper {
bad_reference_wrapper(T&);
bad_reference_wrapper(T&&) = delete;
operator T&() const;
};
namespace std
{
template <typename T>
@ -95,13 +102,16 @@ struct TernaryOp {
>::type type;
};
// (4.1)
// -- If sizeof...(T) is zero, there shall be no member type.
void test_bullet_one() {
static_assert(no_common_type<>::value, "");
}
// If sizeof...(T) is one, let T0 denote the sole type constituting the pack T.
// The member typedef-name type shall denote the same type as decay_t<T0>.
// (4.2)
// -- If sizeof...(T) is one, let T0 denote the sole type constituting the pack
// T. The member typedef-name type shall denote the same type, if any, as
// common_type_t<T0, T0>; otherwise there shall be no member type.
void test_bullet_two() {
static_assert((std::is_same<std::common_type<void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<int>::type, int>::value), "");
@ -122,11 +132,11 @@ void test_bullet_three_one_imp() {
static_assert((std::is_same<typename std::common_type<T, U>::type, typename std::common_type<DT, DU>::type>::value), "");
}
// (3.3)
// (4.3)
// -- If sizeof...(T) is two, let the first and second types constituting T be
// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
// as decay_t<T1> and decay_t<T2>, respectively.
// (3.3.1)
// (4.3.1)
// -- If is_same_v<T1, D1> is false or is_same_v<T2, D2> is false, let C
// denote the same type, if any, as common_type_t<D1, D2>.
void test_bullet_three_one() {
@ -160,16 +170,19 @@ void test_bullet_three_one() {
}
}
// (3.3)
// (4.3)
// -- If sizeof...(T) is two, let the first and second types constituting T be
// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
// as decay_t<T1> and decay_t<T2>, respectively.
// (3.3.1)
// (4.3.1)
// -- If [...]
// (3.3.2)
// -- Otherwise, let C denote the same type, if any, as
// (4.3.2)
// -- [Note: [...]
// (4.3.3)
// -- Otherwise, if
// decay_t<decltype(false ? declval<D1>() : declval<D2>())>
void test_bullet_three_two() {
// denotes a type, let C denote that type.
void test_bullet_three_three() {
{
typedef int const* T1;
typedef int* T2;
@ -200,7 +213,37 @@ void test_bullet_three_two() {
}
}
// (3.4)
// (4.3)
// -- If sizeof...(T) is two, let the first and second types constituting T be
// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
// as decay_t<T1> and decay_t<T2>, respectively.
// (4.3.1)
// -- If [...]
// (4.3.2)
// -- [Note: [...]
// (4.3.3)
// -- Otherwise
// (4.3.4)
// -- Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, let C
// denote the type decay_t<COND-RES(CREF(D1), CREF(D2))>.
void test_bullet_three_four() {
#if TEST_STD_VER >= 20
static_assert(std::is_same_v<std::common_type_t<int, bad_reference_wrapper<int>>, int>, "");
static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<const bad_reference_wrapper<double>, double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<volatile bad_reference_wrapper<double>, double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<const volatile bad_reference_wrapper<double>, double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, const double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, volatile double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, const volatile double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>&, double>, double>, "");
static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, double&>, double>, "");
#endif
}
// (4.4)
// -- If sizeof...(T) is greater than two, let T1, T2, and R, respectively,
// denote the first, second, and (pack of) remaining types constituting T.
// Let C denote the same type, if any, as common_type_t<T1, T2>. If there is
@ -307,7 +350,8 @@ int main(int, char**)
test_bullet_one();
test_bullet_two();
test_bullet_three_one();
test_bullet_three_two();
test_bullet_three_three();
test_bullet_three_four();
test_bullet_four();
// P0548