[libcxx-commits] [libcxx] [libc++][chrono] Applied `[[nodiscard]]` to clocks (PR #174120)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Dec 31 16:56:13 PST 2025
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/174120
>From a100d5be70c91f31671291c5643e9d00af6b6f8b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 1 Jan 2026 01:46:33 +0200
Subject: [PATCH] [libc++][chrono] Applied `[[nodiscard]]` to clocks
In this release:
- [x] `file_clock`
- [x] `steady_clock`
- [x] `system_clock`
- [x] `time_point`
Any other existing clocks are already annotated.
`[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue.
- https://libcxx.llvm.org/CodingGuidelines.html
- https://wg21.link/time.point
- https://wg21.link/time.clock.file
- https://wg21.link/time.clock.steady
- https://wg21.link/time.clock.system
Towards #172124
---
libcxx/include/__chrono/file_clock.h | 6 +-
libcxx/include/__chrono/steady_clock.h | 2 +-
libcxx/include/__chrono/system_clock.h | 6 +-
libcxx/include/__chrono/time_point.h | 34 +++--
.../diagnostics/chrono.nodiscard.verify.cpp | 120 +++++++++++++++---
5 files changed, 130 insertions(+), 38 deletions(-)
diff --git a/libcxx/include/__chrono/file_clock.h b/libcxx/include/__chrono/file_clock.h
index 1885f0facce15..968f652f796d2 100644
--- a/libcxx/include/__chrono/file_clock.h
+++ b/libcxx/include/__chrono/file_clock.h
@@ -60,16 +60,18 @@ struct _FilesystemClock {
_LIBCPP_EXPORTED_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = false;
- _LIBCPP_EXPORTED_FROM_ABI static time_point now() noexcept;
+ [[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI static time_point now() noexcept;
# if _LIBCPP_STD_VER >= 20
template <class _Duration>
+ [[nodiscard]]
_LIBCPP_HIDE_FROM_ABI static chrono::sys_time<_Duration> to_sys(const chrono::file_time<_Duration>& __t) {
return chrono::sys_time<_Duration>(__t.time_since_epoch());
}
template <class _Duration>
- _LIBCPP_HIDE_FROM_ABI static chrono::file_time<_Duration> from_sys(const chrono::sys_time<_Duration>& __t) {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static chrono::file_time<_Duration>
+ from_sys(const chrono::sys_time<_Duration>& __t) {
return chrono::file_time<_Duration>(__t.time_since_epoch());
}
# endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/steady_clock.h b/libcxx/include/__chrono/steady_clock.h
index 1b247b2c28609..8e68c9a3c20f2 100644
--- a/libcxx/include/__chrono/steady_clock.h
+++ b/libcxx/include/__chrono/steady_clock.h
@@ -31,7 +31,7 @@ class _LIBCPP_EXPORTED_FROM_ABI steady_clock {
typedef chrono::time_point<steady_clock, duration> time_point;
static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = true;
- static time_point now() _NOEXCEPT;
+ [[__nodiscard__]] static time_point now() _NOEXCEPT;
};
#endif
diff --git a/libcxx/include/__chrono/system_clock.h b/libcxx/include/__chrono/system_clock.h
index 5a9eb65bdae7a..e3ef75ae50fa6 100644
--- a/libcxx/include/__chrono/system_clock.h
+++ b/libcxx/include/__chrono/system_clock.h
@@ -31,9 +31,9 @@ class _LIBCPP_EXPORTED_FROM_ABI system_clock {
typedef chrono::time_point<system_clock> time_point;
static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = false;
- static time_point now() _NOEXCEPT;
- static time_t to_time_t(const time_point& __t) _NOEXCEPT;
- static time_point from_time_t(time_t __t) _NOEXCEPT;
+ [[__nodiscard__]] static time_point now() _NOEXCEPT;
+ [[__nodiscard__]] static time_t to_time_t(const time_point& __t) _NOEXCEPT;
+ [[__nodiscard__]] static time_point from_time_t(time_t __t) _NOEXCEPT;
};
#if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/time_point.h b/libcxx/include/__chrono/time_point.h
index bc2c7798a630b..773414cc148a7 100644
--- a/libcxx/include/__chrono/time_point.h
+++ b/libcxx/include/__chrono/time_point.h
@@ -54,7 +54,9 @@ class time_point {
// observer
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 duration time_since_epoch() const { return __d_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 duration time_since_epoch() const {
+ return __d_;
+ }
// arithmetic
@@ -82,8 +84,12 @@ class time_point {
// special values
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point min() _NOEXCEPT { return time_point(duration::min()); }
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point max() _NOEXCEPT { return time_point(duration::max()); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point min() _NOEXCEPT {
+ return time_point(duration::min());
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point max() _NOEXCEPT {
+ return time_point(duration::max());
+ }
};
} // namespace chrono
@@ -96,29 +102,32 @@ struct common_type<chrono::time_point<_Clock, _Duration1>, chrono::time_point<_C
namespace chrono {
template <class _ToDuration, class _Clock, class _Duration, __enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, _ToDuration>
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, _ToDuration>
time_point_cast(const time_point<_Clock, _Duration>& __t) {
return time_point<_Clock, _ToDuration>(chrono::duration_cast<_ToDuration>(__t.time_since_epoch()));
}
#if _LIBCPP_STD_VER >= 17
template <class _ToDuration, class _Clock, class _Duration, enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> floor(const time_point<_Clock, _Duration>& __t) {
+[[nodiscard]] inline
+ _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> floor(const time_point<_Clock, _Duration>& __t) {
return time_point<_Clock, _ToDuration>{chrono::floor<_ToDuration>(__t.time_since_epoch())};
}
template <class _ToDuration, class _Clock, class _Duration, enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> ceil(const time_point<_Clock, _Duration>& __t) {
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration>
+ceil(const time_point<_Clock, _Duration>& __t) {
return time_point<_Clock, _ToDuration>{chrono::ceil<_ToDuration>(__t.time_since_epoch())};
}
template <class _ToDuration, class _Clock, class _Duration, enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> round(const time_point<_Clock, _Duration>& __t) {
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration>
+round(const time_point<_Clock, _Duration>& __t) {
return time_point<_Clock, _ToDuration>{chrono::round<_ToDuration>(__t.time_since_epoch())};
}
template <class _Rep, class _Period, enable_if_t<numeric_limits<_Rep>::is_signed, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI constexpr duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) {
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) {
return __d >= __d.zero() ? +__d : -__d;
}
#endif // _LIBCPP_STD_VER >= 17
@@ -188,7 +197,7 @@ operator<=>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock
// time_point operator+(time_point x, duration y);
template <class _Clock, class _Duration1, class _Rep2, class _Period2>
-inline _LIBCPP_HIDE_FROM_ABI
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type>
operator+(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs) {
typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Tr;
@@ -198,7 +207,7 @@ operator+(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Pe
// time_point operator+(duration x, time_point y);
template <class _Rep1, class _Period1, class _Clock, class _Duration2>
-inline _LIBCPP_HIDE_FROM_ABI
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<duration<_Rep1, _Period1>, _Duration2>::type>
operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) {
return __rhs + __lhs;
@@ -207,7 +216,7 @@ operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Dura
// time_point operator-(time_point x, duration y);
template <class _Clock, class _Duration1, class _Rep2, class _Period2>
-inline _LIBCPP_HIDE_FROM_ABI
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type>
operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs) {
typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Ret;
@@ -217,7 +226,8 @@ operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Pe
// duration operator-(time_point x, time_point y);
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename common_type<_Duration1, _Duration2>::type
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
+typename common_type<_Duration1, _Duration2>::type
operator-(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) {
return __lhs.time_since_epoch() - __rhs.time_since_epoch();
}
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
index 4e7380b863993..dde660903dad4 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
@@ -6,9 +6,6 @@
//
//===----------------------------------------------------------------------===//
-// Check that format functions are marked [[nodiscard]] as a conforming extension
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
// XFAIL: libcpp-has-no-experimental-tzdb
@@ -16,10 +13,15 @@
// <chrono>
+// Check that functions are marked [[nodiscard]]
+
#include <chrono>
+#include <ctime>
+#include <ratio>
#include "test_macros.h"
+#if TEST_STD_VER >= 20
// These types have "private" constructors.
void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chrono::leap_second leap) {
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
@@ -75,34 +77,72 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro
t::locate_zone(""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
- { // [time.clock.utc]
+ {
+ std::chrono::zoned_time<std::chrono::seconds> zt;
+
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::utc_clock::now();
+ static_cast<std::chrono::sys_seconds>(zt);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ static_cast<std::chrono::local_seconds>(zt);
+ zt.get_time_zone(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ zt.get_local_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
+}
+#endif // TEST_STD_VER >= 20
+
+void test() {
+#if TEST_STD_VER >= 20
+ { // [time.clock.file]
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::utc_clock::to_sys(std::chrono::utc_seconds{});
+ std::chrono::file_clock::now();
+
+ using Duration = std::chrono::duration<double, std::ratio<1, 30>>;
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::utc_clock::from_sys(std::chrono::sys_seconds{});
+ std::chrono::file_clock::to_sys(std::chrono::file_time<Duration>{});
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::get_leap_second_info(std::chrono::utc_seconds{});
+ std::chrono::file_clock::from_sys(std::chrono::sys_time<Duration>{});
}
+#endif
- {
- std::chrono::zoned_time<std::chrono::seconds> zt;
+#if TEST_STD_VER >= 20
+ { // [time.clock.gps]
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::gps_clock::now();
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- static_cast<std::chrono::sys_seconds>(zt);
+ std::chrono::gps_clock::to_utc(std::chrono::gps_seconds{});
+
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- static_cast<std::chrono::local_seconds>(zt);
+ std::chrono::gps_clock::from_utc(std::chrono::utc_seconds{});
+ }
+#endif // TEST_STD_VER >= 20
- zt.get_time_zone(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- zt.get_local_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ { // [time.clock.steady]
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::steady_clock::now();
}
+ { // [time.clock.system]
+
+ std::chrono::time_point<std::chrono::system_clock> tp;
+ std::time_t time = std::time(nullptr);
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::system_clock::now();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::system_clock::to_time_t(tp);
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::system_clock::from_time_t(time);
+ }
+
+#if TEST_STD_VER >= 20
{ // [time.clock.tai]
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::chrono::tai_clock::now();
@@ -113,15 +153,55 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::chrono::tai_clock::from_utc(std::chrono::utc_seconds{});
}
+#endif
+
+ { // [time.point]
+ std::chrono::time_point<std::chrono::system_clock> tp;
+ std::chrono::duration<double, std::ratio<1, 30> > dr;
- { // [time.clock.gps]
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::gps_clock::now();
+ tp.time_since_epoch();
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::gps_clock::to_utc(std::chrono::gps_seconds{});
+ tp.min();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ tp.max();
+#if TEST_STD_VER >= 17
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::chrono::gps_clock::from_utc(std::chrono::utc_seconds{});
+ std::chrono::floor(tp);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::ceil(tp);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::round(tp);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::abs(dr);
+#endif
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ tp + dr;
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ dr + tp;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ tp - dr;
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ tp - tp;
+ }
+
+#if TEST_STD_VER >= 20
+ { // [time.clock.utc]
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::utc_clock::now();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::utc_clock::to_sys(std::chrono::utc_seconds{});
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::utc_clock::from_sys(std::chrono::sys_seconds{});
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::get_leap_second_info(std::chrono::utc_seconds{});
}
+#endif // TEST_STD_VER >= 20
}
More information about the libcxx-commits
mailing list