diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 316127f44e0d..f0e9c4090f9c 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -192,7 +192,7 @@ "`1203 `__","More useful rvalue stream insertion","Prague","|Complete|","12.0" "`2859 `__","Definition of *reachable* in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object","Prague","","" "`3018 `__","``shared_ptr``\ of function type","Prague","","" -"`3050 `__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","","","|chrono|" +"`3050 `__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","|Complete|","19.0","|chrono|" "`3141 `__","``CopyConstructible``\ doesn't preserve source values","Prague","|Nothing to do|","" "`3150 `__","``UniformRandomBitGenerator``\ should validate ``min``\ and ``max``\ ","Prague","|Complete|","13.0","|ranges|" "`3175 `__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","|Complete|","13.0" diff --git a/libcxx/include/__chrono/duration.h b/libcxx/include/__chrono/duration.h index 5693ee644091..1e81420244b1 100644 --- a/libcxx/include/__chrono/duration.h +++ b/libcxx/include/__chrono/duration.h @@ -412,7 +412,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR template ::type>::value, int> = 0> + __enable_if_t::type>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; @@ -423,7 +423,7 @@ operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { template ::type>::value, int> = 0> + __enable_if_t::type>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> operator*(const _Rep1& __s, const duration<_Rep2, _Period>& __d) { return __d * __s; @@ -435,7 +435,7 @@ template ::value && - is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value, + is_convertible::type>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { @@ -457,7 +457,7 @@ template ::value && - is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value, + is_convertible::type>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { diff --git a/libcxx/include/chrono b/libcxx/include/chrono index c80fa78a56ba..f8407419c954 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -58,7 +58,7 @@ public: constexpr explicit duration(const Rep2& r, typename enable_if < - is_convertible::value && + is_convertible::value && (treat_as_floating_point::value || !treat_as_floating_point::value && !treat_as_floating_point::value) >::type* = 0); diff --git a/libcxx/test/std/time/rep.h b/libcxx/test/std/time/rep.h index 80a0e3c54571..ddb5c0b24931 100644 --- a/libcxx/test/std/time/rep.h +++ b/libcxx/test/std/time/rep.h @@ -10,6 +10,7 @@ #define REP_H #include "test_macros.h" +#include class Rep { @@ -29,6 +30,28 @@ public: struct NotARep {}; +#if TEST_STD_VER >= 11 +// Several duration operators take a Rep parameter. Before LWG3050 this +// parameter was constrained to be convertible from a non-const object, +// but the code always uses a const object. So the function was SFINAE'd +// away for this type. LWG3050 fixes the constraint to use a const +// object. +struct RepConstConvertibleLWG3050 { + operator long() = delete; + operator long() const { return 2; } +}; +namespace std { +template <> +struct common_type { + using type = long; +}; +template <> +struct common_type { + using type = long; +}; +} // namespace std +#endif // TEST_STD_VER >= 11 + // std::chrono:::duration has only '*', '/' and '%' taking a "Rep" parameter // Multiplication is commutative, division is not. diff --git a/libcxx/test/std/time/time.duration/time.duration.nonmember/op_divide_duration.pass.cpp b/libcxx/test/std/time/time.duration/time.duration.nonmember/op_divide_duration.pass.cpp index d580f4edf2fe..6cedd13a13cf 100644 --- a/libcxx/test/std/time/time.duration/time.duration.nonmember/op_divide_duration.pass.cpp +++ b/libcxx/test/std/time/time.duration/time.duration.nonmember/op_divide_duration.pass.cpp @@ -21,6 +21,7 @@ #include "test_macros.h" #include "truncate_fp.h" +#include "../../rep.h" int main(int, char**) { @@ -65,7 +66,17 @@ int main(int, char**) constexpr std::chrono::duration > s2(5); static_assert(s1 / s2 == 20./3, ""); } -#endif + { + std::chrono::duration d(5); + RepConstConvertibleLWG3050 x; - return 0; + { + auto r = d / x; + assert(r.count() == 2); + ASSERT_SAME_TYPE(std::chrono::duration, decltype(r)); + } + } +#endif // TEST_STD_VER >= 11 + + return 0; } diff --git a/libcxx/test/std/time/time.duration/time.duration.nonmember/op_mod_duration.pass.cpp b/libcxx/test/std/time/time.duration/time.duration.nonmember/op_mod_duration.pass.cpp index 8b8b50d940b8..df637e1c23e3 100644 --- a/libcxx/test/std/time/time.duration/time.duration.nonmember/op_mod_duration.pass.cpp +++ b/libcxx/test/std/time/time.duration/time.duration.nonmember/op_mod_duration.pass.cpp @@ -18,6 +18,7 @@ #include #include #include +#include "../../rep.h" #include "test_macros.h" @@ -60,7 +61,17 @@ int main(int, char**) constexpr std::chrono::duration > r = s1 % s2; static_assert(r.count() == 24, ""); } -#endif + { + std::chrono::duration d(5); + RepConstConvertibleLWG3050 x; - return 0; + { + auto r = d % x; + assert(r.count() == 1); + ASSERT_SAME_TYPE(std::chrono::duration, decltype(r)); + } + } +#endif // TEST_STD_VER >= 11 + + return 0; } diff --git a/libcxx/test/std/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp b/libcxx/test/std/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp index c33103231282..d7c8c2da3c32 100644 --- a/libcxx/test/std/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp +++ b/libcxx/test/std/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp @@ -26,28 +26,27 @@ #include "test_macros.h" #include "../../rep.h" -int main(int, char**) -{ - { +int main(int, char**) { + { std::chrono::nanoseconds ns(3); ns = ns * 5; assert(ns.count() == 15); ns = 6 * ns; assert(ns.count() == 90); - } + } #if TEST_STD_VER >= 11 - { + { constexpr std::chrono::nanoseconds ns(3); constexpr std::chrono::nanoseconds ns2 = ns * 5; static_assert(ns2.count() == 15, ""); constexpr std::chrono::nanoseconds ns3 = 6 * ns; static_assert(ns3.count() == 18, ""); - } + } #endif #if TEST_STD_VER >= 11 - { // This is related to PR#41130 + { // This is related to PR#41130 typedef std::chrono::nanoseconds Duration; Duration d(5); NotARep n; @@ -57,8 +56,23 @@ int main(int, char**) assert(d.count() == 5); d = n * d; assert(d.count() == 5); + } + { + std::chrono::duration d(8); + RepConstConvertibleLWG3050 x; + + { + auto r = d * x; + assert(r.count() == 16); + ASSERT_SAME_TYPE(std::chrono::duration, decltype(r)); } -#endif + { + auto r = x * d; + assert(r.count() == 16); + ASSERT_SAME_TYPE(std::chrono::duration, decltype(r)); + } + } +#endif // TEST_STD_VER >= 11 return 0; }