[libcxx-commits] [libcxx] [libc++][chrono] implements GPS clock. (PR #125921)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Feb 9 06:17:48 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Mark de Wever (mordante)
<details>
<summary>Changes</summary>
Completes:
- LWG3359 <chrono> leap second support should allow for negative leap seconds
- P1361 Integration of chrono with text formatting
Implements parts of:
- P0355 Extending <chrono> to Calendars and Time Zones
---
Patch is 83.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125921.diff
18 Files Affected:
- (modified) libcxx/docs/Status/FormatPaper.csv (+1-1)
- (modified) libcxx/include/CMakeLists.txt (+1)
- (modified) libcxx/include/__chrono/convert_to_tm.h (+6)
- (modified) libcxx/include/__chrono/formatter.h (+14)
- (added) libcxx/include/__chrono/gps_clock.h (+90)
- (modified) libcxx/include/__chrono/ostream.h (+7)
- (modified) libcxx/include/chrono (+29)
- (modified) libcxx/include/module.modulemap (+4)
- (modified) libcxx/modules/std/chrono.inc (-2)
- (modified) libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp (+11)
- (added) libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp (+73)
- (added) libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp (+73)
- (added) libcxx/test/std/time/time.clock/time.clock.gps/gps_time.ostream.pass.cpp (+164)
- (added) libcxx/test/std/time/time.clock/time.clock.gps/time.clock.gps.members/from_utc.pass.cpp (+158)
- (added) libcxx/test/std/time/time.clock/time.clock.gps/time.clock.gps.members/now.pass.cpp (+33)
- (added) libcxx/test/std/time/time.clock/time.clock.gps/time.clock.gps.members/to_utc.pass.cpp (+153)
- (added) libcxx/test/std/time/time.clock/time.clock.gps/types.compile.pass.cpp (+60)
- (added) libcxx/test/std/time/time.syn/formatter.gps_time.pass.cpp (+990)
``````````diff
diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv
index beec97b8c01790c..6387b5ac20a3d9a 100644
--- a/libcxx/docs/Status/FormatPaper.csv
+++ b/libcxx/docs/Status/FormatPaper.csv
@@ -4,7 +4,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::sys_time<Duration>``",,Mark de Wever,|Complete|,17
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::utc_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,|Complete|,20
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::tai_time<Duration>``",,Mark de Wever,|Complete|,21
-`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
+`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",,Mark de Wever,|Complete|,21
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::file_time<Duration>``",,Mark de Wever,|Complete|,17
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_time<Duration>``",,Mark de Wever,|Complete|,17
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local-time-format-t<Duration>``",,,|Nothing To Do|,
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index ce805b4eb7b8b4f..4aab32a7850db6e 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -256,6 +256,7 @@ set(files
__chrono/exception.h
__chrono/file_clock.h
__chrono/formatter.h
+ __chrono/gps_clock.h
__chrono/hh_mm_ss.h
__chrono/high_resolution_clock.h
__chrono/leap_second.h
diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h
index d9ccf693160d292..0a6b62772609162 100644
--- a/libcxx/include/__chrono/convert_to_tm.h
+++ b/libcxx/include/__chrono/convert_to_tm.h
@@ -15,6 +15,7 @@
#include <__chrono/day.h>
#include <__chrono/duration.h>
#include <__chrono/file_clock.h>
+#include <__chrono/gps_clock.h>
#include <__chrono/hh_mm_ss.h>
#include <__chrono/local_info.h>
#include <__chrono/month.h>
@@ -124,6 +125,11 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::tai_time<_Duration> __tp) {
return std::__convert_to_tm<_Tm>(chrono::sys_time<_Rp>{__tp.time_since_epoch() - __offset});
}
+template <class _Tm, class _Duration>
+_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::gps_time<_Duration> __tp) {
+ return std::__convert_to_tm<_Tm>(chrono::utc_clock::to_sys(chrono::gps_clock::to_utc(__tp)));
+}
+
# endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index 13bcb717291f699..a5caecce8a4f6ce 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -21,6 +21,7 @@
# include <__chrono/day.h>
# include <__chrono/duration.h>
# include <__chrono/file_clock.h>
+# include <__chrono/gps_clock.h>
# include <__chrono/hh_mm_ss.h>
# include <__chrono/local_info.h>
# include <__chrono/month.h>
@@ -235,6 +236,8 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const
# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
else if constexpr (__is_time_point<_Tp> && requires { requires same_as<typename _Tp::clock, chrono::tai_clock>; })
return {"TAI", chrono::seconds{0}};
+ else if constexpr (__is_time_point<_Tp> && requires { requires same_as<typename _Tp::clock, chrono::gps_clock>; })
+ return {"GPS", chrono::seconds{0}};
else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
return __formatter::__convert_to_time_zone(__value.get_info());
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
@@ -748,6 +751,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter<chrono::tai_time<_Duration>, _CharT> : pub
}
};
+template <class _Duration, __fmt_char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<chrono::gps_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
+public:
+ using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>;
+
+ template <class _ParseContext>
+ _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
+ return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock);
+ }
+};
+
# endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
diff --git a/libcxx/include/__chrono/gps_clock.h b/libcxx/include/__chrono/gps_clock.h
new file mode 100644
index 000000000000000..2e220cab946e368
--- /dev/null
+++ b/libcxx/include/__chrono/gps_clock.h
@@ -0,0 +1,90 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___CHRONO_GPS_CLOCK_H
+#define _LIBCPP___CHRONO_GPS_CLOCK_H
+
+#include <version>
+// Enable the contents of the header only when libc++ was built with experimental features enabled.
+#if _LIBCPP_HAS_EXPERIMENTAL_TZDB
+
+# include <__assert>
+# include <__chrono/duration.h>
+# include <__chrono/time_point.h>
+# include <__chrono/utc_clock.h>
+# include <__config>
+# include <__type_traits/common_type.h>
+
+# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+# endif
+
+_LIBCPP_PUSH_MACROS
+# include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
+
+namespace chrono {
+
+class gps_clock;
+
+template <class _Duration>
+using gps_time = time_point<gps_clock, _Duration>;
+using gps_seconds = gps_time<seconds>;
+
+class gps_clock {
+public:
+ using rep = utc_clock::rep;
+ using period = utc_clock::period;
+ using duration = chrono::duration<rep, period>;
+ using time_point = chrono::time_point<gps_clock>;
+ static constexpr bool is_steady = false; // The utc_clock is not steady.
+
+ // The static difference between UTC and GPS time as specified in the Standard.
+ static constexpr chrono::seconds __offset{315964809};
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); }
+
+ template <class _Duration>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time<common_type_t<_Duration, seconds>>
+ to_utc(const gps_time<_Duration>& __time) noexcept {
+ using _Rp = common_type_t<_Duration, seconds>;
+ _Duration __time_since_epoch = __time.time_since_epoch();
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset,
+ "the GPS to UTC conversion would underflow");
+
+ return utc_time<_Rp>{__time_since_epoch + __offset};
+ }
+
+ template <class _Duration>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static gps_time<common_type_t<_Duration, seconds>>
+ from_utc(const utc_time<_Duration>& __time) noexcept {
+ using _Rp = common_type_t<_Duration, seconds>;
+ _Duration __time_since_epoch = __time.time_since_epoch();
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset,
+ "the UTC to GPS conversion would overflow");
+
+ return gps_time<_Rp>{__time_since_epoch - __offset};
+ }
+};
+
+} // namespace chrono
+
+# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
+ // _LIBCPP_HAS_LOCALIZATION
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
+
+#endif // _LIBCPP___CHRONO_GPS_CLOCK_H
diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h
index b8cd6a4680662b0..7a01b186780cb5e 100644
--- a/libcxx/include/__chrono/ostream.h
+++ b/libcxx/include/__chrono/ostream.h
@@ -18,6 +18,7 @@
# include <__chrono/day.h>
# include <__chrono/duration.h>
# include <__chrono/file_clock.h>
+# include <__chrono/gps_clock.h>
# include <__chrono/hh_mm_ss.h>
# include <__chrono/local_info.h>
# include <__chrono/month.h>
@@ -78,6 +79,12 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const tai_time<_Duration>& __tp
return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp);
}
+template <class _CharT, class _Traits, class _Duration>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
+operator<<(basic_ostream<_CharT, _Traits>& __os, const gps_time<_Duration>& __tp) {
+ return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp);
+}
+
# endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index bd4c98600440c48..8d4adc80dc1e530 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -363,6 +363,33 @@ template<class charT, class traits, class Duration> // C++20
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, const tai_time<Duration>& t);
+// [time.clock.gps], class gps_clock
+class gps_clock { // C++20
+public:
+ using rep = a signed arithmetic type;
+ using period = ratio<unspecified, unspecified>;
+ using duration = chrono::duration<rep, period>;
+ using time_point = chrono::time_point<gps_clock>;
+ static constexpr bool is_steady = unspecified;
+
+ static time_point now();
+
+ template<class Duration>
+ static utc_time<common_type_t<Duration, seconds>>
+ to_utc(const gps_time<Duration>& t);
+ template<class Duration>
+ static gps_time<common_type_t<Duration, seconds>>
+ from_utc(const utc_time<Duration>& t);
+};
+
+template<class Duration>
+using gps_time = time_point<gps_clock, Duration>; // C++20
+using gps_seconds = gps_time<seconds>; // C++20
+
+template<class charT, class traits, class Duration> // C++20
+ basic_ostream<charT, traits>&
+ operator<<(basic_ostream<charT, traits>& os, const gps_time<Duration>& t);
+
class file_clock // C++20
{
public:
@@ -928,6 +955,8 @@ namespace std {
struct formatter<chrono::utc_time<Duration>, charT>; // C++20
template<class Duration, class charT>
struct formatter<chrono::tai_time<Duration>, charT>; // C++20
+ template<class Duration, class charT>
+ struct formatter<chrono::gps_time<Duration>, charT>; // C++20
template<class Duration, class charT>
struct formatter<chrono::filetime<Duration>, charT>; // C++20
template<class Duration, class charT>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index fd39c946b992a43..eb46c2f95e055f8 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -935,6 +935,10 @@ module std [system] {
module exception { header "__chrono/exception.h" }
module file_clock { header "__chrono/file_clock.h" }
module formatter { header "__chrono/formatter.h" }
+ module gps_clock {
+ header "__chrono/gps_clock.h"
+ export std.chrono.time_point
+ }
module hh_mm_ss { header "__chrono/hh_mm_ss.h" }
module high_resolution_clock {
header "__chrono/high_resolution_clock.h"
diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc
index 43e8da36e904489..66eccd8d290ad17 100644
--- a/libcxx/modules/std/chrono.inc
+++ b/libcxx/modules/std/chrono.inc
@@ -103,13 +103,11 @@ export namespace std {
using std::chrono::tai_seconds;
using std::chrono::tai_time;
-# if 0
// [time.clock.gps], class gps_clock
using std::chrono::gps_clock;
using std::chrono::gps_seconds;
using std::chrono::gps_time;
-# endif
# endif // _LIBCPP_ENABLE_EXPERIMENTAL
#endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
index bb40e0cfc4e1b8a..4e7380b86399359 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
@@ -113,4 +113,15 @@ 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{});
}
+
+ { // [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}}
+ std::chrono::gps_clock::to_utc(std::chrono::gps_seconds{});
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::chrono::gps_clock::from_utc(std::chrono::utc_seconds{});
+ }
}
diff --git a/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp
new file mode 100644
index 000000000000000..d8200439d973761
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// REQUIRES: has-unix-headers
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <chrono>
+//
+// class gps_clock;
+
+// static gps_time<common_type_t<_Duration, seconds>>
+// from_utc(const utc_time<_Duration>& t) noexcept;
+
+#include <chrono>
+
+#include "check_assertion.h"
+
+// The function is specified as
+// gps_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} + 378691210s
+// When t == t.max() there will be a signed integral overflow (other values too).
+int main(int, char**) {
+ using namespace std::literals::chrono_literals;
+ constexpr std::chrono::seconds offset{315964809};
+
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::nanoseconds>::max() - offset);
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::nanoseconds>::max() - offset + 1ns),
+ "the UTC to GPS conversion would overflow");
+
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::microseconds>::max() - offset);
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::microseconds>::max() - offset + 1us),
+ "the UTC to GPS conversion would overflow");
+
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::milliseconds>::max() - offset);
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::milliseconds>::max() - offset + 1ms),
+ "the UTC to GPS conversion would overflow");
+
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_seconds::max() - offset);
+ TEST_LIBCPP_ASSERT_FAILURE(std::chrono::gps_clock::from_utc(std::chrono::utc_seconds::max() - offset + 1s),
+ "the UTC to GPS conversion would overflow");
+
+ // The conversion uses `common_type_t<Duration, seconds>` so types "larger"
+ // than seconds are converted to seconds. Types "larger" than seconds are
+ // stored in "smaller" intergral and the overflow can never occur.
+
+ // Validate the types can never overflow on all current (and future) supported platforms.
+ static_assert(std::chrono::utc_time<std::chrono::days>::max() <= std::chrono::utc_seconds::max() - offset);
+ static_assert(std::chrono::utc_time<std::chrono::weeks>::max() <= std::chrono::utc_seconds::max() - offset);
+ static_assert(std::chrono::utc_time<std::chrono::months>::max() <= std::chrono::utc_seconds::max() - offset);
+ static_assert(std::chrono::utc_time<std::chrono::years>::max() <= std::chrono::utc_seconds::max() - offset);
+
+ // Validate the run-time conversion works.
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::days>::max());
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::weeks>::max());
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::months>::max());
+ (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::years>::max());
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp
new file mode 100644
index 000000000000000..d61b3374f661f46
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// REQUIRES: has-unix-headers
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <chrono>
+//
+// class gps_clock;
+
+// static utc_time<common_type_t<_Duration, seconds>>
+// to_utc(const gps_time<_Duration>& t) noexcept;
+
+#include <chrono>
+
+#include "check_assertion.h"
+
+// The function is specified as
+// utc_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} - 378691210s
+// When t == t.min() there will be a signed integral underlow (other values too).
+int main(int, char**) {
+ using namespace std::literals::chrono_literals;
+ constexpr std::chrono::seconds offset{315964809};
+
+ (void)std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::nanoseconds>::min() + offset);
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::nanoseconds>::min() + offset - 1ns),
+ "the GPS to UTC conversion would underflow");
+
+ (void)std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::microseconds>::min() + offset);
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::microseconds>::min() + offset - 1us),
+ "the GPS to UTC conversion would underflow");
+
+ (void)std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::milliseconds>::min() + offset);
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::milliseconds>::min() + offset - 1ms),
+ "the GPS to UTC conversion would underflow");
+
+ (void)std::chrono::gps_clock::to_utc(s...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/125921
More information about the libcxx-commits
mailing list