Skip to content

[libc++][chrono] Implements duration Rep constraints. #80539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx20Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
"`1203 <https://wg21.link/LWG1203>`__","More useful rvalue stream insertion","Prague","|Complete|","12.0"
"`2859 <https://wg21.link/LWG2859>`__","Definition of *reachable* in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object","Prague","",""
"`3018 <https://wg21.link/LWG3018>`__","``shared_ptr``\ of function type","Prague","",""
"`3050 <https://wg21.link/LWG3050>`__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","","","|chrono|"
"`3050 <https://wg21.link/LWG3050>`__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","|Complete|","19.0","|chrono|"
"`3141 <https://wg21.link/LWG3141>`__","``CopyConstructible``\ doesn't preserve source values","Prague","|Nothing to do|",""
"`3150 <https://wg21.link/LWG3150>`__","``UniformRandomBitGenerator``\ should validate ``min``\ and ``max``\ ","Prague","|Complete|","13.0","|ranges|"
"`3175 <https://wg21.link/LWG3175>`__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","|Complete|","13.0"
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/__chrono/duration.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
template <class _Rep1,
class _Period,
class _Rep2,
__enable_if_t<is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
__enable_if_t<is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
typedef typename common_type<_Rep1, _Rep2>::type _Cr;
Expand All @@ -423,7 +423,7 @@ operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
template <class _Rep1,
class _Period,
class _Rep2,
__enable_if_t<is_convertible<_Rep1, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
__enable_if_t<is_convertible<const _Rep1&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
operator*(const _Rep1& __s, const duration<_Rep2, _Period>& __d) {
return __d * __s;
Expand All @@ -435,7 +435,7 @@ template <class _Rep1,
class _Period,
class _Rep2,
__enable_if_t<!__is_duration<_Rep2>::value &&
is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value,
is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value,
int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
Expand All @@ -457,7 +457,7 @@ template <class _Rep1,
class _Period,
class _Rep2,
__enable_if_t<!__is_duration<_Rep2>::value &&
is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value,
is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value,
int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period>
operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public:
constexpr explicit duration(const Rep2& r,
typename enable_if
<
is_convertible<Rep2, rep>::value &&
is_convertible<const Rep2&, rep>::value &&
(treat_as_floating_point<rep>::value ||
!treat_as_floating_point<rep>::value && !treat_as_floating_point<Rep2>::value)
>::type* = 0);
Expand Down
23 changes: 23 additions & 0 deletions libcxx/test/std/time/rep.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define REP_H

#include "test_macros.h"
#include <type_traits>

class Rep
{
Expand All @@ -29,6 +30,28 @@ class Rep

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<RepConstConvertibleLWG3050, int> {
using type = long;
};
template <>
struct common_type<int, RepConstConvertibleLWG3050> {
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "test_macros.h"
#include "truncate_fp.h"
#include "../../rep.h"

int main(int, char**)
{
Expand Down Expand Up @@ -65,7 +66,17 @@ int main(int, char**)
constexpr std::chrono::duration<double, std::ratio<3, 5> > s2(5);
static_assert(s1 / s2 == 20./3, "");
}
#endif
{
std::chrono::duration<int> d(5);
RepConstConvertibleLWG3050 x;

{
auto r = d / x;
assert(r.count() == 2);
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
}
}
#endif // TEST_STD_VER >= 11

return 0;
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <chrono>
#include <cassert>
#include <ratio>
#include "../../rep.h"

#include "test_macros.h"

Expand Down Expand Up @@ -60,7 +61,17 @@ int main(int, char**)
constexpr std::chrono::duration<int, std::ratio<1, 15> > r = s1 % s2;
static_assert(r.count() == 24, "");
}
#endif
{
std::chrono::duration<int> d(5);
RepConstConvertibleLWG3050 x;

{
auto r = d % x;
assert(r.count() == 1);
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
}
}
#endif // TEST_STD_VER >= 11

return 0;
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -57,8 +56,23 @@ int main(int, char**)
assert(d.count() == 5);
d = n * d;
assert(d.count() == 5);
}
{
std::chrono::duration<int> d(8);
RepConstConvertibleLWG3050 x;

{
auto r = d * x;
assert(r.count() == 16);
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
}
#endif
{
auto r = x * d;
assert(r.count() == 16);
ASSERT_SAME_TYPE(std::chrono::duration<long>, decltype(r));
}
}
#endif // TEST_STD_VER >= 11

return 0;
}