Index: libcxx/include/chrono =================================================================== --- libcxx/include/chrono +++ libcxx/include/chrono @@ -1286,10 +1286,43 @@ { }; +template +struct __has_common_type : false_type {}; + +template +struct __has_common_type<_Tp, _Up, typename __void_t::type>::type> : true_type {}; + +template +struct __Fooby2 : false_type {}; + +template +struct __Fooby2<_Rep1, _Rep2, true> : _LIBCPP_BOOL_CONSTANT((is_convertible<_Rep1, typename common_type<_Rep1, _Rep2>::type>::value)) {}; + +template +struct __Fooby : false_type {}; + +template +struct __Fooby<_Rep1, _Period, _Rep2, false> : _LIBCPP_BOOL_CONSTANT((__Fooby2<_Rep1, _Rep2, __has_common_type<_Rep1, _Rep2>::value>::value)) {}; + +template +struct __FoobyRet { typedef void type; }; + +template +struct __FoobyRet<_Rep1, _Period, _Rep2, true> +{ + typedef duration::type, _Period> type; +}; + template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR -typename __duration_divide_result, _Rep2>::type +typename enable_if +< +// !__is_duration<_Rep2>::value && is_convertible<_Rep1, typename common_type<_Rep1, _Rep2>::type>::value, +// duration::type, _Period> + __Fooby<_Rep1, _Period, _Rep2, __is_duration<_Rep2>::value>::value, + typename __FoobyRet<_Rep1, _Period, _Rep2, __Fooby<_Rep1, _Period, _Rep2, __is_duration<_Rep2>::value>::value>::type +>::type operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; @@ -1312,7 +1345,13 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR -typename __duration_divide_result, _Rep2>::type +typename enable_if +< +// !__is_duration<_Rep2>::value && is_convertible<_Rep1, typename common_type<_Rep1, _Rep2>::type>::value, +// duration::type, _Period> + __Fooby<_Rep1, _Period, _Rep2, __is_duration<_Rep2>::value>::value, + typename __FoobyRet<_Rep1, _Period, _Rep2, __Fooby<_Rep1, _Period, _Rep2, __is_duration<_Rep2>::value>::value>::type +>::type operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; Index: libcxx/test/std/utilities/time/rep.h =================================================================== --- libcxx/test/std/utilities/time/rep.h +++ libcxx/test/std/utilities/time/rep.h @@ -25,4 +25,40 @@ Rep& operator/=(Rep x) {data_ /= x.data_; return *this;} }; +// This is PR#41130 + +struct NotARep {}; + +// std::chrono:::duration has only '*', '/' and '%' taking a "Rep" parameter + +// Multiplication is commutative, division is not. +template +std::chrono::duration +operator*(std::chrono::duration d, NotARep) { return d; } + +template +std::chrono::duration +operator*(NotARep, std::chrono::duration d) { return d; } + +template +std::chrono::duration +operator/(std::chrono::duration d, NotARep) { return d; } + +template +std::chrono::duration +operator%(std::chrono::duration d, NotARep) { return d; } + +// op= is not commutative. +template +std::chrono::duration& +operator*=(std::chrono::duration& d, NotARep) { return d; } + +template +std::chrono::duration& +operator/=(std::chrono::duration& d, NotARep) { return d; } + +template +std::chrono::duration& +operator%=(std::chrono::duration& d, NotARep) { return d; } + #endif // REP_H Index: libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_divide=.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_divide=.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_divide=.pass.cpp @@ -16,6 +16,7 @@ #include #include "test_macros.h" +#include "../../rep.h" #if TEST_STD_VER > 14 constexpr bool test_constexpr() @@ -38,5 +39,14 @@ static_assert(test_constexpr(), ""); #endif +#if TEST_STD_VER >= 11 + { // This is PR#41130 + std::chrono::nanoseconds d(5); + NotARep n; + d /= n; + assert(d.count() == 5); + } +#endif + return 0; } Index: libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_mod=duration.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_mod=duration.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_mod=duration.pass.cpp @@ -16,6 +16,7 @@ #include #include "test_macros.h" +#include "../../rep.h" #if TEST_STD_VER > 14 constexpr bool test_constexpr() @@ -42,5 +43,14 @@ static_assert(test_constexpr(), ""); #endif +#if TEST_STD_VER >= 11 + { // This is PR#41130 + std::chrono::nanoseconds d(5); + NotARep n; + d %= n; + assert(d.count() == 5); + } +#endif + return 0; } Index: libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_mod=rep.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_mod=rep.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_mod=rep.pass.cpp @@ -17,6 +17,11 @@ #include "test_macros.h" +class NotARep {}; + +typedef std::chrono::seconds Duration; +Duration operator%=(Duration d, NotARep) { return d; } + #if TEST_STD_VER > 14 constexpr bool test_constexpr() { @@ -38,5 +43,15 @@ static_assert(test_constexpr(), ""); #endif +#if TEST_STD_VER >= 11 + { // This is PR#41130 + Duration d(5); + NotARep n; + d %= n; + assert(d.count() == 5); + } +#endif + + return 0; } Index: libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_times=.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_times=.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.arithmetic/op_times=.pass.cpp @@ -16,6 +16,7 @@ #include #include "test_macros.h" +#include "../../rep.h" #if TEST_STD_VER > 14 constexpr bool test_constexpr() @@ -38,5 +39,14 @@ static_assert(test_constexpr(), ""); #endif +#if TEST_STD_VER >= 11 + { // This is PR#41130 + std::chrono::nanoseconds d(5); + NotARep n; + d *= n; + assert(d.count() == 5); + } +#endif + return 0; } Index: libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_divide_rep.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_divide_rep.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_divide_rep.pass.cpp @@ -19,11 +19,14 @@ #include #include "test_macros.h" +#include "../../rep.h" int main(int, char**) { { - std::chrono::nanoseconds ns(15); + typedef std::chrono::nanoseconds Dur; + Dur ns(15); + ASSERT_SAME_TYPE(Dur, decltype(ns / 5)); ns = ns / 5; assert(ns.count() == 3); } @@ -35,5 +38,16 @@ } #endif +#if TEST_STD_VER >= 11 + { // This is PR#41130 + typedef std::chrono::nanoseconds Duration; + Duration d(5); + NotARep n; + ASSERT_SAME_TYPE(Duration, decltype(d / n)); + d = d / n; + assert(d.count() == 5); + } +#endif + return 0; } Index: libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_mod_rep.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_mod_rep.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_mod_rep.pass.cpp @@ -19,11 +19,14 @@ #include #include "test_macros.h" +#include "../../rep.h" int main(int, char**) { { - std::chrono::nanoseconds ns(15); + typedef std::chrono::nanoseconds Dur; + Dur ns(15); + ASSERT_SAME_TYPE(Dur, decltype(ns % 6)); ns = ns % 6; assert(ns.count() == 3); } @@ -35,5 +38,16 @@ } #endif +#if TEST_STD_VER >= 11 + { // This is PR#41130 + typedef std::chrono::seconds Duration; + Duration d(5); + NotARep n; + ASSERT_SAME_TYPE(Duration, decltype(d % n)); + d = d % n; + assert(d.count() == 5); + } +#endif + return 0; } Index: libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp =================================================================== --- libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp +++ libcxx/test/std/utilities/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp @@ -24,6 +24,7 @@ #include #include "test_macros.h" +#include "../../rep.h" int main(int, char**) { @@ -34,6 +35,7 @@ ns = 6 * ns; assert(ns.count() == 90); } + #if TEST_STD_VER >= 11 { constexpr std::chrono::nanoseconds ns(3); @@ -44,5 +46,19 @@ } #endif +#if TEST_STD_VER >= 11 + { // This is related to PR#41130 + typedef std::chrono::nanoseconds Duration; + Duration d(5); + NotARep n; + ASSERT_SAME_TYPE(Duration, decltype(d * n)); + ASSERT_SAME_TYPE(Duration, decltype(n * d)); + d = d * n; + assert(d.count() == 5); + d = n * d; + assert(d.count() == 5); + } +#endif + return 0; }