Skip to content

Commit 7d9540e

Browse files
mordanteh-vetinari
andauthored
[libc++][chrono] Implements duration Rep constraints. (llvm#80539)
Applies LWG3050 to the constraints of operator*, operator/, and operator%. The changes to the constructor were done in https://reviews.llvm.org/D118902, but that patch did not identify the related LWG-issue, and only adjusted the constructor to the wording in the Standard. Implements: - LWG 3050: Conversion specification problem in chrono::duration constructor --------- Co-authored-by: h-vetinari <[email protected]>
1 parent 33c6b77 commit 7d9540e

File tree

7 files changed

+77
-18
lines changed

7 files changed

+77
-18
lines changed

libcxx/docs/Status/Cxx20Issues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@
192192
"`1203 <https://wg21.link/LWG1203>`__","More useful rvalue stream insertion","Prague","|Complete|","12.0"
193193
"`2859 <https://wg21.link/LWG2859>`__","Definition of *reachable* in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object","Prague","",""
194194
"`3018 <https://wg21.link/LWG3018>`__","``shared_ptr``\ of function type","Prague","",""
195-
"`3050 <https://wg21.link/LWG3050>`__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","","","|chrono|"
195+
"`3050 <https://wg21.link/LWG3050>`__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","|Complete|","19.0","|chrono|"
196196
"`3141 <https://wg21.link/LWG3141>`__","``CopyConstructible``\ doesn't preserve source values","Prague","|Nothing to do|",""
197197
"`3150 <https://wg21.link/LWG3150>`__","``UniformRandomBitGenerator``\ should validate ``min``\ and ``max``\ ","Prague","|Complete|","13.0","|ranges|"
198198
"`3175 <https://wg21.link/LWG3175>`__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","|Complete|","13.0"

libcxx/include/__chrono/duration.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
412412
template <class _Rep1,
413413
class _Period,
414414
class _Rep2,
415-
__enable_if_t<is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
415+
__enable_if_t<is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
416416
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
417417
operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
418418
typedef typename common_type<_Rep1, _Rep2>::type _Cr;
@@ -423,7 +423,7 @@ operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
423423
template <class _Rep1,
424424
class _Period,
425425
class _Rep2,
426-
__enable_if_t<is_convertible<_Rep1, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
426+
__enable_if_t<is_convertible<const _Rep1&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
427427
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
428428
operator*(const _Rep1& __s, const duration<_Rep2, _Period>& __d) {
429429
return __d * __s;
@@ -435,7 +435,7 @@ template <class _Rep1,
435435
class _Period,
436436
class _Rep2,
437437
__enable_if_t<!__is_duration<_Rep2>::value &&
438-
is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value,
438+
is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value,
439439
int> = 0>
440440
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
441441
operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
@@ -457,7 +457,7 @@ template <class _Rep1,
457457
class _Period,
458458
class _Rep2,
459459
__enable_if_t<!__is_duration<_Rep2>::value &&
460-
is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value,
460+
is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value,
461461
int> = 0>
462462
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
463463
operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {

libcxx/include/chrono

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public:
5858
constexpr explicit duration(const Rep2& r,
5959
typename enable_if
6060
<
61-
is_convertible<Rep2, rep>::value &&
61+
is_convertible<const Rep2&, rep>::value &&
6262
(treat_as_floating_point<rep>::value ||
6363
!treat_as_floating_point<rep>::value && !treat_as_floating_point<Rep2>::value)
6464
>::type* = 0);

libcxx/test/std/time/rep.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define REP_H
1111

1212
#include "test_macros.h"
13+
#include <type_traits>
1314

1415
class Rep
1516
{
@@ -29,6 +30,28 @@ class Rep
2930

3031
struct NotARep {};
3132

33+
#if TEST_STD_VER >= 11
34+
// Several duration operators take a Rep parameter. Before LWG3050 this
35+
// parameter was constrained to be convertible from a non-const object,
36+
// but the code always uses a const object. So the function was SFINAE'd
37+
// away for this type. LWG3050 fixes the constraint to use a const
38+
// object.
39+
struct RepConstConvertibleLWG3050 {
40+
operator long() = delete;
41+
operator long() const { return 2; }
42+
};
43+
namespace std {
44+
template <>
45+
struct common_type<RepConstConvertibleLWG3050, int> {
46+
using type = long;
47+
};
48+
template <>
49+
struct common_type<int, RepConstConvertibleLWG3050> {
50+
using type = long;
51+
};
52+
} // namespace std
53+
#endif // TEST_STD_VER >= 11
54+
3255
// std::chrono:::duration has only '*', '/' and '%' taking a "Rep" parameter
3356

3457
// Multiplication is commutative, division is not.

libcxx/test/std/time/time.duration/time.duration.nonmember/op_divide_duration.pass.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "test_macros.h"
2323
#include "truncate_fp.h"
24+
#include "../../rep.h"
2425

2526
int main(int, char**)
2627
{
@@ -65,7 +66,17 @@ int main(int, char**)
6566
constexpr std::chrono::duration<double, std::ratio<3, 5> > s2(5);
6667
static_assert(s1 / s2 == 20./3, "");
6768
}
68-
#endif
69+
{
70+
std::chrono::duration<int> d(5);
71+
RepConstConvertibleLWG3050 x;
72+
73+
{
74+
auto r = d / x;
75+
assert(r.count() == 2);
76+
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
77+
}
78+
}
79+
#endif // TEST_STD_VER >= 11
6980

70-
return 0;
81+
return 0;
7182
}

libcxx/test/std/time/time.duration/time.duration.nonmember/op_mod_duration.pass.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <chrono>
1919
#include <cassert>
2020
#include <ratio>
21+
#include "../../rep.h"
2122

2223
#include "test_macros.h"
2324

@@ -60,7 +61,17 @@ int main(int, char**)
6061
constexpr std::chrono::duration<int, std::ratio<1, 15> > r = s1 % s2;
6162
static_assert(r.count() == 24, "");
6263
}
63-
#endif
64+
{
65+
std::chrono::duration<int> d(5);
66+
RepConstConvertibleLWG3050 x;
67+
68+
{
69+
auto r = d % x;
70+
assert(r.count() == 1);
71+
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
72+
}
73+
}
74+
#endif // TEST_STD_VER >= 11
6475

65-
return 0;
76+
return 0;
6677
}

libcxx/test/std/time/time.duration/time.duration.nonmember/op_times_rep.pass.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,27 @@
2626
#include "test_macros.h"
2727
#include "../../rep.h"
2828

29-
int main(int, char**)
30-
{
31-
{
29+
int main(int, char**) {
30+
{
3231
std::chrono::nanoseconds ns(3);
3332
ns = ns * 5;
3433
assert(ns.count() == 15);
3534
ns = 6 * ns;
3635
assert(ns.count() == 90);
37-
}
36+
}
3837

3938
#if TEST_STD_VER >= 11
40-
{
39+
{
4140
constexpr std::chrono::nanoseconds ns(3);
4241
constexpr std::chrono::nanoseconds ns2 = ns * 5;
4342
static_assert(ns2.count() == 15, "");
4443
constexpr std::chrono::nanoseconds ns3 = 6 * ns;
4544
static_assert(ns3.count() == 18, "");
46-
}
45+
}
4746
#endif
4847

4948
#if TEST_STD_VER >= 11
50-
{ // This is related to PR#41130
49+
{ // This is related to PR#41130
5150
typedef std::chrono::nanoseconds Duration;
5251
Duration d(5);
5352
NotARep n;
@@ -57,8 +56,23 @@ int main(int, char**)
5756
assert(d.count() == 5);
5857
d = n * d;
5958
assert(d.count() == 5);
59+
}
60+
{
61+
std::chrono::duration<int> d(8);
62+
RepConstConvertibleLWG3050 x;
63+
64+
{
65+
auto r = d * x;
66+
assert(r.count() == 16);
67+
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
6068
}
61-
#endif
69+
{
70+
auto r = x * d;
71+
assert(r.count() == 16);
72+
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
73+
}
74+
}
75+
#endif // TEST_STD_VER >= 11
6276

6377
return 0;
6478
}

0 commit comments

Comments
 (0)