From f61a12b3957d4ec67b2c0f4999c7054f1cf8f605 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 7 May 2019 23:46:39 +0100 Subject: [PATCH] PR libstdc++/89102 implement new common_type rules (P0435R1, P0548R1) This change ensures that std::common_type<> is a complete type (LWG 2408), and that std::common_type, std::common_type, and std::common_type will use program-defined specializations for std::common_type (LWG 2465). The implementation of common_type is changed to use void_t, and the specializations for duration and time_point are modified to also use void_t instead of depending on implementation details of common_type. PR libstdc++/89102 * doc/xml/manual/intro.xml: Document DR 2408 and 2465 changes. * include/std/chrono (__duration_common_type_wrapper): Replace with ... (__duration_common_type): New helper. (common_type, chrono::duration>): Use __duration_common_type. (__timepoint_common_type_wrapper): Replace with ... (__timepoint_common_type): New helper. (common_type, chrono::time_point>): Use __time_point_common_type. * include/std/type_traits (common_type<>): Define, as per LWG 2408. (__common_type_impl): If either argument is transformed by decay, use the common_type of the decayed types. (__common_type_impl<_Tp, _Up, _Tp, _Up>): If the types are already decayed, use __do_common_type_impl to get the common_type. (common_type<_Tp>): Use common_type<_Tp, _Tp>. (__do_member_type_wrapper, __member_type_wrapper) (__expanded_common_type_wrapper): Remove. (__common_type_pack, __common_type_fold): New helpers. (common_type<_Tp, _Up, _Vp...>): Use new helpers instead of __member_type_wrapper and __expanded_common_type_wrapper. * testsuite/20_util/common_type/requirements/explicit_instantiation.cc: Test zero-length template argument list. * testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc: Test single argument cases and argument types that should decay. * testsuite/20_util/common_type/requirements/sfinae_friendly_2.cc: Adjust expected error. * testsuite/20_util/duration/literals/range_neg.cc: Use zero for dg-error lineno. * testsuite/20_util/duration/requirements/typedefs_neg1.cc: Likewise. * testsuite/20_util/duration/requirements/typedefs_neg2.cc: Likewise. * testsuite/20_util/duration/requirements/typedefs_neg3.cc: Likewise. From-SVN: r270987 --- libstdc++-v3/ChangeLog | 33 ++++++ libstdc++-v3/doc/xml/manual/intro.xml | 20 ++++ libstdc++-v3/include/std/chrono | 45 ++++---- libstdc++-v3/include/std/type_traits | 102 ++++++++++-------- .../requirements/sfinae_friendly_1.cc | 6 +- .../20_util/duration/literals/range_neg.cc | 2 +- .../duration/requirements/typedefs_neg1.cc | 2 +- .../duration/requirements/typedefs_neg2.cc | 2 +- .../duration/requirements/typedefs_neg3.cc | 2 +- 9 files changed, 145 insertions(+), 69 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e8c625b98a4..fb69a3d1050 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,38 @@ 2019-05-07 Jonathan Wakely + PR libstdc++/89102 + * doc/xml/manual/intro.xml: Document DR 2408 and 2465 changes. + * include/std/chrono (__duration_common_type_wrapper): Replace with ... + (__duration_common_type): New helper. + (common_type, chrono::duration>): Use + __duration_common_type. + (__timepoint_common_type_wrapper): Replace with ... + (__timepoint_common_type): New helper. + (common_type, chrono::time_point>): + Use __time_point_common_type. + * include/std/type_traits (common_type<>): Define, as per LWG 2408. + (__common_type_impl): If either argument is transformed by decay, + use the common_type of the decayed types. + (__common_type_impl<_Tp, _Up, _Tp, _Up>): If the types are already + decayed, use __do_common_type_impl to get the common_type. + (common_type<_Tp>): Use common_type<_Tp, _Tp>. + (__do_member_type_wrapper, __member_type_wrapper) + (__expanded_common_type_wrapper): Remove. + (__common_type_pack, __common_type_fold): New helpers. + (common_type<_Tp, _Up, _Vp...>): Use new helpers instead of + __member_type_wrapper and __expanded_common_type_wrapper. + * testsuite/20_util/common_type/requirements/explicit_instantiation.cc: + Test zero-length template argument list. + * testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc: + Test single argument cases and argument types that should decay. + * testsuite/20_util/common_type/requirements/sfinae_friendly_2.cc: + Adjust expected error. + * testsuite/20_util/duration/literals/range_neg.cc: Use zero for + dg-error lineno. + * testsuite/20_util/duration/requirements/typedefs_neg1.cc: Likewise. + * testsuite/20_util/duration/requirements/typedefs_neg2.cc: Likewise. + * testsuite/20_util/duration/requirements/typedefs_neg3.cc: Likewise. + * doc/xml/manual/intro.xml: Fix DR 2537 and DR 2566 confusion. 2019-05-01 Nina Dinka Ranns diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index 518981559a0..35a2016f5c3 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -1045,6 +1045,17 @@ requirements of the license of GCC. Remove explicit from the constructor. + 2408: + SFINAE-friendly + common_type/iterator_traits + is missing in C++14 + + + Make iterator_traits empty if any of the + types is not present in the iterator. + Make common_type<> empty. + + 2415: Inconsistency between unique_ptr and shared_ptr @@ -1105,6 +1116,15 @@ requirements of the license of GCC. Add debug mode assertion. + 2465: + SFINAE-friendly common_type is nearly impossible + to specialize correctly and regresses key functionality + + + Detect whether decay_t changes either type + and use the decayed types if so. + + 2466: allocator_traits::max_size() default behavior is incorrect diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index 1d6326cdd55..b7c1d750067 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -67,48 +67,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 20.11.4.3 specialization of common_type (for duration, sfinae-friendly) + template + struct __duration_common_type + { }; + template - struct __duration_common_type_wrapper + struct __duration_common_type<_CT, _Period1, _Period2, + __void_t> { private: - typedef __static_gcd<_Period1::num, _Period2::num> __gcd_num; - typedef __static_gcd<_Period1::den, _Period2::den> __gcd_den; - typedef typename _CT::type __cr; - typedef ratio<__gcd_num::value, - (_Period1::den / __gcd_den::value) * _Period2::den> __r; + using __gcd_num = __static_gcd<_Period1::num, _Period2::num>; + using __gcd_den = __static_gcd<_Period1::den, _Period2::den>; + using __cr = typename _CT::type; + using __r = ratio<__gcd_num::value, + (_Period1::den / __gcd_den::value) * _Period2::den>; + public: - typedef __success_type> type; + using type = chrono::duration<__cr, __r>; }; template - struct __duration_common_type_wrapper<__failure_type, _Period1, _Period2> + struct __duration_common_type<__failure_type, _Period1, _Period2> { typedef __failure_type type; }; template struct common_type, - chrono::duration<_Rep2, _Period2>> - : public __duration_common_type_wrapper>::type, _Period1, _Period2>::type + chrono::duration<_Rep2, _Period2>> + : __duration_common_type, _Period1, _Period2> { }; // 20.11.4.3 specialization of common_type (for time_point, sfinae-friendly) + template + struct __timepoint_common_type + { }; + template - struct __timepoint_common_type_wrapper + struct __timepoint_common_type<_CT, _Clock, __void_t> { - typedef __success_type> - type; + using type = chrono::time_point<_Clock, typename _CT::type>; }; - template - struct __timepoint_common_type_wrapper<__failure_type, _Clock> - { typedef __failure_type type; }; - template struct common_type, - chrono::time_point<_Clock, _Duration2>> - : public __timepoint_common_type_wrapper>::type, _Clock>::type + chrono::time_point<_Clock, _Duration2>> + : __timepoint_common_type, _Clock> { }; namespace chrono diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 1d14c751cfa..ea733e7b7b2 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2106,6 +2106,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct conditional { typedef _Iffalse type; }; + // __void_t (std::void_t for C++11) + template using __void_t = void; + /// common_type template struct common_type; @@ -2115,65 +2118,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __do_common_type_impl { template - static __success_type() - : std::declval<_Up>())>::type> _S_test(int); + using __cond_t + = decltype(true ? std::declval<_Tp>() : std::declval<_Up>()); + + template + static __success_type>::type> + _S_test(int); template - static __failure_type _S_test(...); + static __failure_type + _S_test(...); }; - template - struct __common_type_impl - : private __do_common_type_impl - { - typedef decltype(_S_test<_Tp, _Up>(0)) type; - }; - - struct __do_member_type_wrapper - { - template - static __success_type _S_test(int); + // If sizeof...(T) is zero, there shall be no member type. + template<> + struct common_type<> + { }; - template - static __failure_type _S_test(...); - }; + // If sizeof...(T) is one, the same type, if any, as common_type_t. + template + struct common_type<_Tp0> + : public common_type<_Tp0, _Tp0> + { }; - template - struct __member_type_wrapper - : private __do_member_type_wrapper + // If sizeof...(T) is two, ... + template::type, + typename _Dp2 = typename decay<_Tp2>::type> + struct __common_type_impl { - typedef decltype(_S_test<_Tp>(0)) type; + // If is_same_v is false or is_same_v is false, + // let C denote the same type, if any, as common_type_t. + using type = common_type<_Dp1, _Dp2>; }; - template - struct __expanded_common_type_wrapper + template + struct __common_type_impl<_Tp1, _Tp2, _Tp1, _Tp2> + : private __do_common_type_impl { - typedef common_type type; + // Otherwise, if decay_t() : declval())> + // denotes a valid type, let C denote that type. + using type = decltype(_S_test<_Tp1, _Tp2>(0)); }; - template - struct __expanded_common_type_wrapper<__failure_type, _Args...> - { typedef __failure_type type; }; + // If sizeof...(T) is two, ... + template + struct common_type<_Tp1, _Tp2> + : public __common_type_impl<_Tp1, _Tp2>::type + { }; - template<> - struct common_type<> + template + struct __common_type_pack { }; - template - struct common_type<_Tp> - : common_type<_Tp, _Tp> + template + struct __common_type_fold; + + // If sizeof...(T) is greater than two, ... + template + struct common_type<_Tp1, _Tp2, _Rp...> + : public __common_type_fold, + __common_type_pack<_Rp...>> { }; - template - struct common_type<_Tp, _Up> - : public __common_type_impl<_Tp, _Up>::type + // Let C denote the same type, if any, as common_type_t. + // If there is such a type C, type shall denote the same type, if any, + // as common_type_t. + template + struct __common_type_fold<_CTp, __common_type_pack<_Rp...>, + __void_t> + : public common_type { }; - template - struct common_type<_Tp, _Up, _Vp...> - : public __expanded_common_type_wrapper>::type, _Vp...>::type + // Otherwise, there shall be no member type. + template + struct __common_type_fold<_CTp, _Rp, void> { }; template::value> @@ -2446,9 +2465,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using __enable_if_t = typename enable_if<_Cond, _Tp>::type; - // __void_t (std::void_t for C++11) - template using __void_t = void; - #if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++11 #define __cpp_lib_void_t 201411 /// A metafunction that always yields void, used for detecting valid types. diff --git a/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc b/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc index 9b94eb13434..a54da7c24b2 100644 --- a/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc +++ b/libstdc++-v3/testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc @@ -214,6 +214,7 @@ static_assert(is_type, static_assert(is_type, void(*)()>(), ""); static_assert(is_type, int>, int>(), ""); +static_assert(is_type, int>, int>(), ""); static_assert(is_type, ImplicitTo>, ImplicitTo>(), ""); static_assert(is_type, int, @@ -260,19 +261,22 @@ static_assert(is_type, Ukn>(), ""); static_assert(is_type, RX12>(), ""); +static_assert(is_type, RX12>(), ""); +static_assert(is_type, RX12>(), ""); +static_assert(is_type, RX12>(), ""); static_assert(is_type, RX21>(), ""); static_assert(is_type, Y1>(), ""); static_assert(is_type, Y3>(), ""); static_assert(is_type, RX12>(), ""); +static_assert(is_type, RX12>(), ""); static_assert(is_type, Y1>(), ""); static_assert(!has_type>(), ""); static_assert(!has_type>(), ""); static_assert(!has_type>(), ""); static_assert(!has_type>(), ""); -static_assert(!has_type, int>>(), ""); static_assert(!has_type, int>>(), ""); static_assert(!has_type, int>>(), ""); diff --git a/libstdc++-v3/testsuite/20_util/duration/literals/range_neg.cc b/libstdc++-v3/testsuite/20_util/duration/literals/range_neg.cc index 1c3ee90c4a6..8be1be5423f 100644 --- a/libstdc++-v3/testsuite/20_util/duration/literals/range_neg.cc +++ b/libstdc++-v3/testsuite/20_util/duration/literals/range_neg.cc @@ -26,6 +26,6 @@ test01() // std::numeric_limits::max() == 9223372036854775807; auto h = 9223372036854775808h; - // { dg-error "cannot be represented" "" { target *-*-* } 908 } + // { dg-error "cannot be represented by duration" "" { target *-*-* } 0 } } // { dg-prune-output "in .constexpr. expansion" } // needed for -O0 diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc index 9181488a612..9c25552892d 100644 --- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc +++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc @@ -29,4 +29,4 @@ void test01() test_type d; // { dg-error "required from here" } } -// { dg-error "rep cannot be a duration" "" { target *-*-* } 316 } +// { dg-error "rep cannot be a duration" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc index e3e450ebf6b..e6029fc782a 100644 --- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc +++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc @@ -30,5 +30,5 @@ void test01() test_type d; // { dg-error "required from here" } } -// { dg-error "must be a specialization of ratio" "" { target *-*-* } 317 } +// { dg-error "must be a specialization of ratio" "" { target *-*-* } 0 } // { dg-prune-output "not a member" } diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc index de0c6659b24..ed8baa195c7 100644 --- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc +++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc @@ -31,4 +31,4 @@ void test01() test_type d; // { dg-error "required from here" } } -// { dg-error "period must be positive" "" { target *-*-* } 319 } +// { dg-error "period must be positive" "" { target *-*-* } 0 } -- 2.30.2