SFINAE out duration converting constructor if the constructor would otherwise cause a ratio compile-time overflow. This fixes LWG 2094.
llvm-svn: 189722
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 69bc206547c3b9f413673ef0ebc6e425c6dbd11a
diff --git a/include/chrono b/include/chrono
index 9fb7743..afc5181 100644
--- a/include/chrono
+++ b/include/chrono
@@ -409,6 +409,37 @@
static_assert(!__is_duration<_Rep>::value, "A duration representation can not be a duration");
static_assert(__is_ratio<_Period>::value, "Second template parameter of duration must be a std::ratio");
static_assert(_Period::num > 0, "duration period must be positive");
+
+ template <class _R1, class _R2>
+ struct __no_overflow
+ {
+ private:
+ static const intmax_t __gcd_n1_n2 = __static_gcd<_R1::num, _R2::num>::value;
+ static const intmax_t __gcd_d1_d2 = __static_gcd<_R1::den, _R2::den>::value;
+ static const intmax_t __n1 = _R1::num / __gcd_n1_n2;
+ static const intmax_t __d1 = _R1::den / __gcd_d1_d2;
+ static const intmax_t __n2 = _R2::num / __gcd_n1_n2;
+ static const intmax_t __d2 = _R2::den / __gcd_d1_d2;
+ static const intmax_t max = -((intmax_t(1) << (sizeof(intmax_t) * CHAR_BIT - 1)) + 1);
+
+ template <intmax_t _Xp, intmax_t _Yp, bool __overflow>
+ struct __mul // __overflow == false
+ {
+ static const intmax_t value = _Xp * _Yp;
+ };
+
+ template <intmax_t _Xp, intmax_t _Yp>
+ struct __mul<_Xp, _Yp, true>
+ {
+ static const intmax_t value = 1;
+ };
+
+ public:
+ static const bool value = (__n1 <= max / __d2) && (__n2 <= max / __d1);
+ typedef ratio<__mul<__n1, __d2, !value>::value,
+ __mul<__n2, __d1, !value>::value> type;
+ };
+
public:
typedef _Rep rep;
typedef _Period period;
@@ -440,9 +471,10 @@
duration(const duration<_Rep2, _Period2>& __d,
typename enable_if
<
+ __no_overflow<_Period2, period>::value && (
treat_as_floating_point<rep>::value ||
- (ratio_divide<_Period2, period>::type::den == 1 &&
- !treat_as_floating_point<_Rep2>::value)
+ (__no_overflow<_Period2, period>::type::den == 1 &&
+ !treat_as_floating_point<_Rep2>::value))
>::type* = 0)
: __rep_(_VSTD::chrono::duration_cast<duration>(__d).count()) {}