From: Eric Fiselier Date: Sun, 31 Mar 2019 20:49:06 +0000 (+0000) Subject: Make common_type's implementation common X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b0e79823d699d9a0c65edb7f425d55a305cccde3;p=platform%2Fupstream%2Fllvm.git Make common_type's implementation common Summary: Currently the C++03 implementation of common_type has much different behavior than the C++11 one. This causes bugs, including inside ``. This patch unifies the two implementations as best it can. The more code they share, the less their behavior can diverge. Reviewers: mclow.lists, ldionne, sbenza Reviewed By: mclow.lists, ldionne Subscribers: libcxx-commits Tags: #libc Differential Revision: https://reviews.llvm.org/D59678 llvm-svn: 357370 --- diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index cd67eb8..2b79490 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -2117,43 +2117,63 @@ struct _LIBCPP_TEMPLATE_VIS make_unsigned template using make_unsigned_t = typename make_unsigned<_Tp>::type; #endif -#ifdef _LIBCPP_HAS_NO_VARIADICS +template +struct __common_type2_imp {}; -template -struct _LIBCPP_TEMPLATE_VIS common_type +template +struct __common_type2_imp<_Tp, _Up, + typename __void_t() : _VSTD::declval<_Up>() + )>::type> { -public: - typedef typename common_type::type, _Vp>::type type; + typedef typename decay() : _VSTD::declval<_Up>() + )>::type type; }; -template <> -struct _LIBCPP_TEMPLATE_VIS common_type -{ -public: - typedef void type; -}; +template +struct __common_type_impl {}; -template -struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, void, void> -{ -public: - typedef typename common_type<_Tp, _Tp>::type type; -}; +// Clang provides variadic templates in C++03 as an extension. +#if !defined(_LIBCPP_CXX03_LANG) || defined(__clang__) +# define _LIBCPP_OPTIONAL_PACK(...) , __VA_ARGS__ +template +struct __common_types; +template +struct _LIBCPP_TEMPLATE_VIS common_type; +#else +# define _LIBCPP_OPTIONAL_PACK(...) +struct __no_arg; +template +struct __common_types; +template +struct common_type { + static_assert(sizeof(_Unused) == 0, + "common_type accepts at most 3 arguments in C++03"); +}; +#endif // _LIBCPP_CXX03_LANG template -struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, void> +struct __common_type_impl< + __common_types<_Tp, _Up>, + typename __void_t::type>::type> { - typedef typename decay() : _VSTD::declval<_Up>() - )>::type type; + typedef typename common_type<_Tp, _Up>::type type; }; -#else // _LIBCPP_HAS_NO_VARIADICS +template +struct __common_type_impl< + __common_types<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)>, + typename __void_t::type>::type> + : __common_type_impl<__common_types::type, + _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> > { +}; // bullet 1 - sizeof...(Tp) == 0 -template -struct _LIBCPP_TEMPLATE_VIS common_type {}; +template <> +struct _LIBCPP_TEMPLATE_VIS common_type<> {}; // bullet 2 - sizeof...(Tp) == 1 @@ -2163,68 +2183,29 @@ struct _LIBCPP_TEMPLATE_VIS common_type<_Tp> // bullet 3 - sizeof...(Tp) == 2 -template -struct __common_type2_imp {}; - -template -struct __common_type2_imp<_Tp, _Up, - typename __void_t() : _VSTD::declval<_Up>() - )>::type> -{ - typedef typename decay() : _VSTD::declval<_Up>() - )>::type type; -}; - -template ::type, - class _DUp = typename decay<_Up>::type> -using __common_type2 = - typename conditional< - is_same<_Tp, _DTp>::value && is_same<_Up, _DUp>::value, - __common_type2_imp<_Tp, _Up>, - common_type<_DTp, _DUp> - >::type; - template struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up> - : __common_type2<_Tp, _Up> {}; + : conditional< + is_same<_Tp, typename decay<_Tp>::type>::value && is_same<_Up, typename decay<_Up>::type>::value, + __common_type2_imp<_Tp, _Up>, + common_type::type, typename decay<_Up>::type> + >::type +{}; // bullet 4 - sizeof...(Tp) > 2 -template struct __common_types; - -template -struct __common_type_impl {}; - -template -struct __common_type_impl< - __common_types<_Tp, _Up>, - typename __void_t::type>::type> -{ - typedef typename common_type<_Tp, _Up>::type type; -}; +template +struct _LIBCPP_TEMPLATE_VIS + common_type<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> + : __common_type_impl< + __common_types<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> > {}; -template -struct __common_type_impl<__common_types<_Tp, _Up, _Vp...>, - typename __void_t::type>::type> - : __common_type_impl< - __common_types::type, _Vp...> > -{ - -}; - -template -struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, _Vp...> - : __common_type_impl<__common_types<_Tp, _Up, _Vp...> > {}; +#undef _LIBCPP_OPTIONAL_PACK #if _LIBCPP_STD_VER > 11 template using common_type_t = typename common_type<_Tp...>::type; #endif -#endif // _LIBCPP_HAS_NO_VARIADICS - // is_assignable template struct __select_2nd { typedef _Tp type; }; diff --git a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp index f96603b..a6b2f62 100644 --- a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp @@ -48,40 +48,53 @@ namespace std template <> struct common_type< ::X, ::X > {}; } -#if TEST_STD_VER >= 11 +template struct VoidT { typedef void type; }; + +#if TEST_STD_VER < 11 +template +struct no_common_type_imp : std::true_type {}; + +template +struct no_common_type_imp::type> + : std::false_type {}; + +struct NoArgTag; + +template +struct no_common_type : no_common_type_imp > {}; +template +struct no_common_type : no_common_type_imp > { +}; +template +struct no_common_type : no_common_type_imp > {}; +template <> +struct no_common_type<> : no_common_type_imp > {}; +#else template struct always_bool_imp { using type = bool; }; template using always_bool = typename always_bool_imp::type; template constexpr auto no_common_type_imp(int) - -> always_bool::type> - { return false; } +-> always_bool::type> +{ return false; } template constexpr bool no_common_type_imp(long) { return true; } template using no_common_type = std::integral_constant(0)>; - -template -using Decay = typename std::decay::type; - -template -using CommonType = typename std::common_type::type; +#endif template -struct TernaryOpImp { - static_assert(std::is_same, T1>::value, "must be same"); - static_assert(std::is_same, T2>::value, "must be same"); - using type = typename std::decay< +struct TernaryOp { + static_assert((std::is_same::type, T1>::value), "must be same"); + static_assert((std::is_same::type, T2>::value), "must be same"); + typedef typename std::decay< decltype(false ? std::declval() : std::declval()) - >::type; + >::type type; }; -template -using TernaryOp = typename TernaryOpImp::type; - // -- If sizeof...(T) is zero, there shall be no member type. void test_bullet_one() { static_assert(no_common_type<>::value, ""); @@ -90,23 +103,23 @@ void test_bullet_one() { // 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. void test_bullet_two() { - static_assert(std::is_same, void>::value, ""); - static_assert(std::is_same, int>::value, ""); - static_assert(std::is_same, int>::value, ""); - static_assert(std::is_same, int volatile*>::value, ""); - static_assert(std::is_same, void(*)()>::value, ""); + static_assert((std::is_same::type, void>::value), ""); + static_assert((std::is_same::type, int>::value), ""); + static_assert((std::is_same::type, int>::value), ""); + static_assert((std::is_same::type, int volatile*>::value), ""); + static_assert((std::is_same::type, void(*)()>::value), ""); - static_assert(no_common_type >::value, ""); + static_assert((no_common_type >::value), ""); } template void test_bullet_three_one_imp() { - using DT = Decay; - using DU = Decay; - static_assert(!std::is_same::value || !std::is_same::value, ""); - static_assert(std::is_same, Expect>::value, ""); - static_assert(std::is_same, Expect>::value, ""); - static_assert(std::is_same, CommonType>::value, ""); + typedef typename std::decay::type DT; + typedef typename std::decay::type DU; + static_assert((!std::is_same::value || !std::is_same::value), ""); + static_assert((std::is_same::type, Expect>::value), ""); + static_assert((std::is_same::type, Expect>::value), ""); + static_assert((std::is_same::type, typename std::common_type::type>::value), ""); } // (3.3) @@ -120,30 +133,30 @@ void test_bullet_three_one() { // Test that the user provided specialization of common_type is used after // decaying T1. { - using T1 = S const; - using T2 = int; + typedef const S T1; + typedef int T2; test_bullet_three_one_imp >(); } // Test a user provided specialization that does not provide a typedef. { - using T1 = ::S const; - using T2 = long; - static_assert(no_common_type::value, ""); - static_assert(no_common_type::value, ""); + typedef const ::S T1; + typedef long T2; + static_assert((no_common_type::value), ""); + static_assert((no_common_type::value), ""); } // Test that the ternary operator is not applied when the types are the // same. { - using T1 = const void; - using Expect = void; - static_assert(std::is_same, Expect>::value, ""); - static_assert(std::is_same, CommonType>::value, ""); + typedef const void T1; + typedef void Expect; + static_assert((std::is_same::type, Expect>::value), ""); + static_assert((std::is_same::type, std::common_type::type>::value), ""); } { - using T1 = int const[]; - using Expect = int const*; - static_assert(std::is_same, Expect>::value, ""); - static_assert(std::is_same, CommonType>::value, ""); + typedef int const T1[]; + typedef int const* Expect; + static_assert((std::is_same::type, Expect>::value), ""); + static_assert((std::is_same::type, std::common_type::type>::value), ""); } } @@ -158,32 +171,32 @@ void test_bullet_three_one() { // decay_t() : declval())> void test_bullet_three_two() { { - using T1 = int const*; - using T2 = int*; - using Expect = TernaryOp; - static_assert(std::is_same, Expect>::value, ""); - static_assert(std::is_same, Expect>::value, ""); + typedef int const* T1; + typedef int* T2; + typedef TernaryOp::type Expect; + static_assert((std::is_same::type, Expect>::value), ""); + static_assert((std::is_same::type, Expect>::value), ""); } // Test that there is no ::type member when the ternary op is ill-formed { - using T1 = int; - using T2 = void; - static_assert(no_common_type::value, ""); - static_assert(no_common_type::value, ""); + typedef int T1; + typedef void T2; + static_assert((no_common_type::value), ""); + static_assert((no_common_type::value), ""); } { - using T1 = int; - using T2 = X; - static_assert(no_common_type::value, ""); - static_assert(no_common_type::value, ""); + typedef int T1; + typedef X T2; + static_assert((no_common_type::value), ""); + static_assert((no_common_type::value), ""); } // Test that the ternary operator is not applied when the types are the // same. { - using T1 = void; - using Expect = void; - static_assert(std::is_same, Expect>::value, ""); - static_assert(std::is_same, CommonType>::value, ""); + typedef void T1; + typedef void Expect; + static_assert((std::is_same::type, Expect>::value), ""); + static_assert((std::is_same::type, std::common_type::type>::value), ""); } } @@ -196,10 +209,12 @@ void test_bullet_three_two() { // no member type. void test_bullet_four() { { // test that there is no ::type member - static_assert(no_common_type::value, ""); - static_assert(no_common_type::value, ""); - static_assert(no_common_type::value, ""); - static_assert(no_common_type::value, ""); + static_assert((no_common_type::value), ""); + static_assert((no_common_type::value), ""); +#if TEST_STD_VER >= 11 + static_assert((no_common_type::value), ""); + static_assert((no_common_type::value), ""); +#endif } } @@ -207,8 +222,8 @@ void test_bullet_four() { // The example code specified in Note B for common_type namespace note_b_example { -using PF1 = bool (&)(); -using PF2 = short (*)(long); +typedef bool (&PF1)(); +typedef short (*PF2)(long); struct S { operator PF2() const; @@ -217,22 +232,24 @@ struct S { char data; }; -using PMF = void (S::*)(long) const; -using PMD = char S::*; +typedef void (S::*PMF)(long) const; +typedef char S::*PMD; using std::is_same; using std::result_of; using std::unique_ptr; -static_assert(is_same::type, short>::value, "Error!"); -static_assert(is_same::type, double>::value, "Error!"); -static_assert(is_same::type, bool>::value, "Error!"); -static_assert(is_same, int)>::type, void>::value, "Error!"); -static_assert(is_same::type, char&&>::value, "Error!"); -static_assert(is_same::type, const char&>::value, "Error!"); +static_assert((is_same::type, short>::value), "Error!"); +static_assert((is_same::type, double>::value), "Error!"); +static_assert((is_same::type, bool>::value), "Error!"); +static_assert((is_same, int)>::type, void>::value), "Error!"); +#if TEST_STD_VER >= 11 +static_assert((is_same::type, char&&>::value), "Error!"); +#endif +static_assert((is_same::type, const char&>::value), "Error!"); } // namespace note_b_example -#endif // TEST_STD_VER >= 11 + int main(int, char**) { @@ -286,13 +303,12 @@ int main(int, char**) static_assert((std::is_same, S >::type, S >::value), ""); static_assert((std::is_same >::type, S >::value), ""); -#if TEST_STD_VER >= 11 + test_bullet_one(); test_bullet_two(); test_bullet_three_one(); test_bullet_three_two(); test_bullet_four(); -#endif // P0548 static_assert((std::is_same >::type, S >::value), ""); @@ -308,5 +324,10 @@ int main(int, char**) static_assert((std::is_same::type, int>::value), ""); static_assert((std::is_same::type, int>::value), ""); +#if TEST_STD_VER >= 11 + // Test that we're really variadic in C++11 + static_assert(std::is_same::type, int>::value, ""); +#endif + return 0; }