[libcxx-commits] [libcxx] 80cab52 - [libc++][chrono] Applied `[[nodiscard]]` to `duration` (#174121)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 6 00:05:26 PST 2026


Author: Hristo Hristov
Date: 2026-01-06T10:05:22+02:00
New Revision: 80cab521d0b8ec91e1b82b028215f2a6d07fe3aa

URL: https://github.com/llvm/llvm-project/commit/80cab521d0b8ec91e1b82b028215f2a6d07fe3aa
DIFF: https://github.com/llvm/llvm-project/commit/80cab521d0b8ec91e1b82b028215f2a6d07fe3aa.diff

LOG: [libc++][chrono] Applied `[[nodiscard]]` to `duration` (#174121)

`[[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.duration

Towards #172124

Added: 
    

Modified: 
    libcxx/include/__chrono/duration.h
    libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__chrono/duration.h b/libcxx/include/__chrono/duration.h
index 01432bd3fa259..8b8877aa9a175 100644
--- a/libcxx/include/__chrono/duration.h
+++ b/libcxx/include/__chrono/duration.h
@@ -104,7 +104,8 @@ struct __duration_cast<_FromDuration, _ToDuration, _Period, false, false> {
 };
 
 template <class _ToDuration, class _Rep, class _Period, __enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration duration_cast(const duration<_Rep, _Period>& __fd) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration
+duration_cast(const duration<_Rep, _Period>& __fd) {
   return __duration_cast<duration<_Rep, _Period>, _ToDuration>()(__fd);
 }
 
@@ -119,14 +120,18 @@ inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<_Rep>:
 template <class _Rep>
 struct duration_values {
 public:
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep zero() _NOEXCEPT { return _Rep(0); }
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep max() _NOEXCEPT { return numeric_limits<_Rep>::max(); }
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep min() _NOEXCEPT { return numeric_limits<_Rep>::lowest(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep zero() _NOEXCEPT { return _Rep(0); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep max() _NOEXCEPT {
+    return numeric_limits<_Rep>::max();
+  }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep min() _NOEXCEPT {
+    return numeric_limits<_Rep>::lowest();
+  }
 };
 
 #if _LIBCPP_STD_VER >= 17
 template <class _ToDuration, class _Rep, class _Period, enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration<_Rep, _Period>& __d) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration<_Rep, _Period>& __d) {
   _ToDuration __t = chrono::duration_cast<_ToDuration>(__d);
   if (__t > __d)
     __t = __t - _ToDuration{1};
@@ -134,7 +139,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration<
 }
 
 template <class _ToDuration, class _Rep, class _Period, enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_Rep, _Period>& __d) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_Rep, _Period>& __d) {
   _ToDuration __t = chrono::duration_cast<_ToDuration>(__d);
   if (__t < __d)
     __t = __t + _ToDuration{1};
@@ -142,7 +147,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_
 }
 
 template <class _ToDuration, class _Rep, class _Period, enable_if_t<__is_duration_v<_ToDuration>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration round(const duration<_Rep, _Period>& __d) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration round(const duration<_Rep, _Period>& __d) {
   _ToDuration __lower = chrono::floor<_ToDuration>(__d);
   _ToDuration __upper = __lower + _ToDuration{1};
   auto __lower_
diff    = __d - __lower;
@@ -222,14 +227,14 @@ class duration {
 
   // observer
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR rep count() const { return __rep_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR rep count() const { return __rep_; }
 
   // arithmetic
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator+() const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator+() const {
     return typename common_type<duration>::type(*this);
   }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator-() const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator-() const {
     return typename common_type<duration>::type(-__rep_);
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator++() {
@@ -271,13 +276,13 @@ class duration {
 
   // special values
 
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration zero() _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration zero() _NOEXCEPT {
     return duration(duration_values<rep>::zero());
   }
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration min() _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration min() _NOEXCEPT {
     return duration(duration_values<rep>::min());
   }
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration max() _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration max() _NOEXCEPT {
     return duration(duration_values<rep>::max());
   }
 };
@@ -391,7 +396,7 @@ operator<=>(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Perio
 // Duration +
 
 template <class _Rep1, class _Period1, class _Rep2, class _Period2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
 typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type
 operator+(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) {
   typedef typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type _Cd;
@@ -401,7 +406,7 @@ operator+(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2
 // Duration -
 
 template <class _Rep1, class _Period1, class _Rep2, class _Period2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
 typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type
 operator-(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) {
   typedef typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type _Cd;
@@ -414,7 +419,8 @@ template <class _Rep1,
           class _Period,
           class _Rep2,
           __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>
+[[__nodiscard__]] 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;
   typedef duration<_Cr, _Period> _Cd;
@@ -425,7 +431,8 @@ template <class _Rep1,
           class _Period,
           class _Rep2,
           __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>
+[[__nodiscard__]] 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;
 }
@@ -438,7 +445,8 @@ template <class _Rep1,
           __enable_if_t<!__is_duration_v<_Rep2> &&
                             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>
+[[__nodiscard__]] 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;
   typedef duration<_Cr, _Period> _Cd;
@@ -446,7 +454,7 @@ operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
 }
 
 template <class _Rep1, class _Period1, class _Rep2, class _Period2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<_Rep1, _Rep2>::type
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<_Rep1, _Rep2>::type
 operator/(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) {
   typedef typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type _Ct;
   return _Ct(__lhs).count() / _Ct(__rhs).count();
@@ -460,7 +468,8 @@ template <class _Rep1,
           __enable_if_t<!__is_duration_v<_Rep2> &&
                             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>
+[[__nodiscard__]] 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;
   typedef duration<_Cr, _Period> _Cd;
@@ -468,7 +477,7 @@ operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) {
 }
 
 template <class _Rep1, class _Period1, class _Rep2, class _Period2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
 typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type
 operator%(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) {
   typedef typename common_type<_Rep1, _Rep2>::type _Cr;
@@ -483,51 +492,53 @@ operator%(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2
 inline namespace literals {
 inline namespace chrono_literals {
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::hours operator""h(unsigned long long __h) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::hours operator""h(unsigned long long __h) {
   return chrono::hours(static_cast<chrono::hours::rep>(__h));
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<3600, 1>> operator""h(long double __h) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<3600, 1>>
+operator""h(long double __h) {
   return chrono::duration<long double, ratio<3600, 1>>(__h);
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::minutes operator""min(unsigned long long __m) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::minutes operator""min(unsigned long long __m) {
   return chrono::minutes(static_cast<chrono::minutes::rep>(__m));
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<60, 1>> operator""min(long double __m) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<60, 1>>
+operator""min(long double __m) {
   return chrono::duration<long double, ratio<60, 1>>(__m);
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::seconds operator""s(unsigned long long __s) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::seconds operator""s(unsigned long long __s) {
   return chrono::seconds(static_cast<chrono::seconds::rep>(__s));
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double> operator""s(long double __s) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double> operator""s(long double __s) {
   return chrono::duration<long double>(__s);
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::milliseconds operator""ms(unsigned long long __ms) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::milliseconds operator""ms(unsigned long long __ms) {
   return chrono::milliseconds(static_cast<chrono::milliseconds::rep>(__ms));
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, milli> operator""ms(long double __ms) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, milli> operator""ms(long double __ms) {
   return chrono::duration<long double, milli>(__ms);
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::microseconds operator""us(unsigned long long __us) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::microseconds operator""us(unsigned long long __us) {
   return chrono::microseconds(static_cast<chrono::microseconds::rep>(__us));
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, micro> operator""us(long double __us) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, micro> operator""us(long double __us) {
   return chrono::duration<long double, micro>(__us);
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::nanoseconds operator""ns(unsigned long long __ns) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::nanoseconds operator""ns(unsigned long long __ns) {
   return chrono::nanoseconds(static_cast<chrono::nanoseconds::rep>(__ns));
 }
 
-_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, nano> operator""ns(long double __ns) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, nano> operator""ns(long double __ns) {
   return chrono::duration<long double, nano>(__ns);
 }
 

diff  --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
index 4e7380b863993..700dcc37c34ef 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
@@ -17,6 +17,7 @@
 // <chrono>
 
 #include <chrono>
+#include <ratio>
 
 #include "test_macros.h"
 
@@ -124,4 +125,91 @@ 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::gps_clock::from_utc(std::chrono::utc_seconds{});
   }
+
+  { // [time.duration]
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::microseconds(2));
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration_values<int>::zero();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration_values<int>::max();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration_values<int>::min();
+
+    std::chrono::duration<int, std::ratio<1, 30> > dr;
+
+#if TEST_STD_VER >= 17
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::floor<std::chrono::seconds>(dr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::ceil<std::chrono::seconds>(dr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::round<std::chrono::seconds>(dr);
+#endif
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr.count();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    +dr;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    -dr;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration<int, std::ratio<1, 30> >::zero();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration<int, std::ratio<1, 30> >::max();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::duration<int, std::ratio<1, 30> >::min();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr + dr;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr - dr;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr * 94;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94 * dr;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr / 82;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr / dr;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr % 47;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    dr % dr;
+
+    using namespace std::chrono_literals;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94h;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    82.5h;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94min;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    82.5min;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94s;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    82.5s;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94ms;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    82.5ms;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94us;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    82.5us;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    94ns;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    82.5ns;
+  }
 }


        


More information about the libcxx-commits mailing list