[llvm-branch-commits] [libcxx] [libc++][chrono] Loads leap-seconds.list in tzdb. (PR #82113)
Mark de Wever via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Feb 17 07:50:05 PST 2024
https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/82113
>From 3710cf0f9e8fa6065b25123e9b2158079e10805c Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Fri, 23 Sep 2022 18:33:20 +0200
Subject: [PATCH] [libc++][chrono] Loads leap-seconds.list in tzdb.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This implements the loading of the leap-seconds.list file and store its
contents in the tzdb struct.
This adds the required `leap_seconds` member.
The class leap_seconds is fully implemented including its non-member
functions.
Implements parts of:
- P0355 Extending <chrono> to Calendars and Time Zones
- P1614 The Mothership has Landed
Implements:
- P1981 Rename leap to leap_second
- LWG3359 <chrono> leap second support should allow for negative leap seconds
- LWG3383 ยง[time.zone.leap.nonmembers] sys_seconds should be replaced with seconds
---
libcxx/docs/Status/Cxx20Issues.csv | 4 +-
libcxx/docs/Status/Cxx20Papers.csv | 2 +-
libcxx/docs/Status/SpaceshipProjects.csv | 2 +-
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__chrono/leap_second.h | 112 ++++++++++++++++++
libcxx/include/__chrono/tzdb.h | 3 +
libcxx/include/chrono | 39 ++++++
libcxx/include/libcxx.imp | 1 +
libcxx/include/module.modulemap.in | 1 +
libcxx/modules/std/chrono.inc | 28 ++---
libcxx/src/CMakeLists.txt | 1 +
libcxx/src/include/tzdb/leap_second_private.h | 27 +++++
libcxx/src/tzdb.cpp | 41 +++++++
...rono.nodiscard_extensions.compile.pass.cpp | 6 +
.../chrono.nodiscard_extensions.verify.cpp | 6 +
.../time.zone.db/leap_seconds.pass.cpp | 102 ++++++++++++++++
.../time.zone.db.access/get_tzdb.pass.cpp | 3 +
.../time.zone.leap/assign.copy.pass.cpp | 56 +++++++++
.../time.zone.leap/cons.copy.pass.cpp | 51 ++++++++
.../time.zone.leap/members/date.pass.cpp | 48 ++++++++
.../time.zone.leap/members/value.pass.cpp | 48 ++++++++
.../nonmembers/comparison.pass.cpp | 77 ++++++++++++
libcxx/test/support/test_chrono_leap_second.h | 53 +++++++++
23 files changed, 693 insertions(+), 19 deletions(-)
create mode 100644 libcxx/include/__chrono/leap_second.h
create mode 100644 libcxx/src/include/tzdb/leap_second_private.h
create mode 100644 libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp
create mode 100644 libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp
create mode 100644 libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp
create mode 100644 libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp
create mode 100644 libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp
create mode 100644 libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp
create mode 100644 libcxx/test/support/test_chrono_leap_second.h
diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index f0e9c4090f9cf6..db57b15256a62f 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -269,7 +269,7 @@
"`3355 <https://wg21.link/LWG3355>`__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|"
"`3356 <https://wg21.link/LWG3356>`__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0"
"`3358 <https://wg21.link/LWG3358>`__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","|Complete|","17.0"
-"`3359 <https://wg21.link/LWG3359>`__","``<chrono>``\ leap second support should allow for negative leap seconds","Prague","","","|chrono|"
+"`3359 <https://wg21.link/LWG3359>`__","``<chrono>``\ leap second support should allow for negative leap seconds","Prague","|Complete|","19.0","|chrono|"
"`3360 <https://wg21.link/LWG3360>`__","``three_way_comparable_with``\ is inconsistent with similar concepts","Prague","|Nothing To Do|","","|spaceship|"
"`3362 <https://wg21.link/LWG3362>`__","Strike ``stop_source``\ 's ``operator!=``\ ","Prague","",""
"`3363 <https://wg21.link/LWG3363>`__","``drop_while_view``\ should opt-out of ``sized_range``\ ","Prague","|Nothing To Do|","","|ranges|"
@@ -286,7 +286,7 @@
"`3380 <https://wg21.link/LWG3380>`__","``common_type``\ and comparison categories","Prague","|Complete|","15.0","|spaceship|"
"`3381 <https://wg21.link/LWG3381>`__","``begin``\ and ``data``\ must agree for ``contiguous_range``\ ","Prague","|Nothing To Do|","","|ranges|"
"`3382 <https://wg21.link/LWG3382>`__","NTTP for ``pair``\ and ``array``\ ","Prague","",""
-"`3383 <https://wg21.link/LWG3383>`__","|sect|\ [time.zone.leap.nonmembers] ``sys_seconds``\ should be replaced with ``seconds``\ ","Prague","","","|chrono|"
+"`3383 <https://wg21.link/LWG3383>`__","|sect|\ [time.zone.leap.nonmembers] ``sys_seconds``\ should be replaced with ``seconds``\ ","Prague","|Complete|","19.0","|chrono|"
"`3384 <https://wg21.link/LWG3384>`__","``transform_view::*sentinel*``\ has an incorrect ``operator-``\ ","Prague","|Complete|","15.0","|ranges|"
"`3385 <https://wg21.link/LWG3385>`__","``common_iterator``\ is not sufficiently constrained for non-copyable iterators","Prague","|Complete|","15.0","|ranges|"
"`3387 <https://wg21.link/LWG3387>`__","|sect|\ [range.reverse.view] ``reverse_view<V>``\ unintentionally requires ``range<const V>``\ ","Prague","|Complete|","15.0","|ranges|"
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index db6491419a5cc3..77078b11a72780 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -179,7 +179,7 @@
"`P1970R2 <https://wg21.link/P1970R2>`__","LWG","Consistency for size() functions: Add ranges::ssize","Prague","|Complete|","15.0","|ranges|"
"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","|Complete|","16.0"
"`P1976R2 <https://wg21.link/P1976R2>`__","LWG","Fixed-size span construction from dynamic range","Prague","|Complete|","11.0","|ranges|"
-"`P1981R0 <https://wg21.link/P1981R0>`__","LWG","Rename leap to leap_second","Prague","* *",""
+"`P1981R0 <https://wg21.link/P1981R0>`__","LWG","Rename leap to leap_second","Prague","|Complete|","19.0","|chrono|"
"`P1982R0 <https://wg21.link/P1982R0>`__","LWG","Rename link to time_zone_link","Prague","|Complete|","19.0","|chrono|"
"`P1983R0 <https://wg21.link/P1983R0>`__","LWG","Wording for GB301, US296, US292, US291, and US283","Prague","|Complete|","15.0","|ranges|"
"`P1994R1 <https://wg21.link/P1994R1>`__","LWG","elements_view needs its own sentinel","Prague","|Complete|","16.0","|ranges|"
diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index c8221078e9a8df..3d14f487d9a910 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -173,7 +173,7 @@ Section,Description,Dependencies,Assignee,Complete
| `year_month_weekday_last <https://reviews.llvm.org/D152699>`_",None,Hristo Hristov,|Complete|
`[time.zone.nonmembers] <https://wg21.link/time.zone.nonmembers>`_,"`chrono::time_zone`",A ``<chrono>`` implementation,Mark de Wever,|Complete|
`[time.zone.zonedtime.nonmembers] <https://wg21.link/time.zone.zonedtime.nonmembers>`_,"`chrono::zoned_time`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
-`[time.zone.leap.nonmembers] <https://wg21.link/time.zone.leap.nonmembers>`_,"`chrono::time_leap_seconds`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
+`[time.zone.leap.nonmembers] <https://wg21.link/time.zone.leap.nonmembers>`_,"`chrono::time_leap_seconds`",A ``<chrono>`` implementation,Mark de Wever,|Complete|
`[time.zone.link.nonmembers] <https://wg21.link/time.zone.link.nonmembers>`_,"`chrono::time_zone_link`",A ``<chrono>`` implementation,Mark de Wever,|Complete|
- `5.13 Clause 28: Localization library <https://wg21.link/p1614r2#clause-28-localization-library>`_,,,,
"| `[locale] <https://wg21.link/locale>`_
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fa3b464e56c4d0..e550e6bfcdefd3 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -281,6 +281,7 @@ set(files
__chrono/formatter.h
__chrono/hh_mm_ss.h
__chrono/high_resolution_clock.h
+ __chrono/leap_second.h
__chrono/literals.h
__chrono/month.h
__chrono/month_weekday.h
diff --git a/libcxx/include/__chrono/leap_second.h b/libcxx/include/__chrono/leap_second.h
new file mode 100644
index 00000000000000..7c1f5ff72498e4
--- /dev/null
+++ b/libcxx/include/__chrono/leap_second.h
@@ -0,0 +1,112 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
+
+#ifndef _LIBCPP___CHRONO_LEAP_SECOND_H
+#define _LIBCPP___CHRONO_LEAP_SECOND_H
+
+#include <version>
+// Enable the contents of the header only when libc++ was built with experimental features enabled.
+#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+# include <__chrono/duration.h>
+# include <__chrono/system_clock.h>
+# include <__chrono/time_point.h>
+# include <__compare/ordering.h>
+# include <__compare/three_way_comparable.h>
+# include <__config>
+
+# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+# endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+# if _LIBCPP_STD_VER >= 20
+
+namespace chrono {
+
+class leap_second {
+public:
+ struct __constructor_tag;
+ [[nodiscard]]
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr leap_second(__constructor_tag&&, sys_seconds __date, seconds __value)
+ : __date_(__date), __value_(__value) {}
+
+ _LIBCPP_HIDE_FROM_ABI leap_second(const leap_second&) = default;
+ _LIBCPP_HIDE_FROM_ABI leap_second& operator=(const leap_second&) = default;
+
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr sys_seconds date() const noexcept { return __date_; }
+
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr seconds value() const noexcept { return __value_; }
+
+private:
+ sys_seconds __date_;
+ seconds __value_;
+};
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const leap_second& __x, const leap_second& __y) {
+ return __x.date() == __y.date();
+}
+_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const leap_second& __x, const leap_second& __y) {
+ return __x.date() <=> __y.date();
+}
+
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const leap_second& __x, const sys_time<_Duration>& __y) {
+ return __x.date() == __y;
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const leap_second& __x, const sys_time<_Duration>& __y) {
+ return __x.date() < __y;
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const sys_time<_Duration>& __x, const leap_second& __y) {
+ return __x < __y.date();
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const leap_second& __x, const sys_time<_Duration>& __y) {
+ return __y < __x;
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const sys_time<_Duration>& __x, const leap_second& __y) {
+ return __y < __x;
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const leap_second& __x, const sys_time<_Duration>& __y) {
+ return !(__y < __x);
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const sys_time<_Duration>& __x, const leap_second& __y) {
+ return !(__y < __x);
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const leap_second& __x, const sys_time<_Duration>& __y) {
+ return !(__x < __y);
+}
+template <class _Duration>
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const sys_time<_Duration>& __x, const leap_second& __y) {
+ return !(__x < __y);
+}
+template <class _Duration>
+ requires three_way_comparable_with<sys_seconds, sys_time<_Duration>>
+_LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const leap_second& __x, const sys_time<_Duration>& __y) {
+ return __x.date() <=> __y;
+}
+
+} // namespace chrono
+
+# endif //_LIBCPP_STD_VER >= 20
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+#endif // _LIBCPP___CHRONO_LEAP_SECOND_H
diff --git a/libcxx/include/__chrono/tzdb.h b/libcxx/include/__chrono/tzdb.h
index 582172e5df9ddb..45c20f279f9c96 100644
--- a/libcxx/include/__chrono/tzdb.h
+++ b/libcxx/include/__chrono/tzdb.h
@@ -16,6 +16,7 @@
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+# include <__chrono/leap_second.h>
# include <__chrono/time_zone.h>
# include <__chrono/time_zone_link.h>
# include <__config>
@@ -40,6 +41,8 @@ struct tzdb {
string version;
vector<time_zone> zones;
vector<time_zone_link> links;
+
+ vector<leap_second> leap_seconds;
};
} // namespace chrono
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index fe73f7c772b996..01ba15d97f3d20 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -688,6 +688,7 @@ struct tzdb {
string version;
vector<time_zone> zones;
vector<time_zone_link> links;
+ vector<leap_second> leap_seconds;
};
class tzdb_list { // C++20
@@ -731,6 +732,43 @@ class time_zone {
bool operator==(const time_zone& x, const time_zone& y) noexcept; // C++20
strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept; // C++20
+// [time.zone.leap], leap second support
+class leap_second { // C++20
+public:
+ leap_second(const leap_second&) = default;
+ leap_second& operator=(const leap_second&) = default;
+
+ // unspecified additional constructors
+
+ constexpr sys_seconds date() const noexcept;
+ constexpr seconds value() const noexcept;
+};
+
+constexpr bool operator==(const leap_second& x, const leap_second& y); // C++20
+constexpr strong_ordering operator<=>(const leap_second& x, const leap_second& y);
+
+template<class Duration> // C++20
+ constexpr bool operator==(const leap_second& x, const sys_time<Duration>& y);
+template<class Duration> // C++20
+ constexpr bool operator< (const leap_second& x, const sys_time<Duration>& y);
+template<class Duration> // C++20
+ constexpr bool operator< (const sys_time<Duration>& x, const leap_second& y);
+template<class Duration> // C++20
+ constexpr bool operator> (const leap_second& x, const sys_time<Duration>& y);
+template<class Duration> // C++20
+ constexpr bool operator> (const sys_time<Duration>& x, const leap_second& y);
+template<class Duration> // C++20
+ constexpr bool operator<=(const leap_second& x, const sys_time<Duration>& y);
+template<class Duration> // C++20
+ constexpr bool operator<=(const sys_time<Duration>& x, const leap_second& y);
+template<class Duration> // C++20
+ constexpr bool operator>=(const leap_second& x, const sys_time<Duration>& y);
+template<class Duration> // C++20
+ constexpr bool operator>=(const sys_time<Duration>& x, const leap_second& y);
+template<class Duration> // C++20
+ requires three_way_comparable_with<sys_seconds, sys_time<Duration>>
+ constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y);
+
// [time.zone.link], class time_zone_link
class time_zone_link { // C++20
public:
@@ -863,6 +901,7 @@ constexpr chrono::year operator ""y(unsigned lo
#if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <__chrono/leap_second.h>
# include <__chrono/time_zone.h>
# include <__chrono/time_zone_link.h>
# include <__chrono/tzdb.h>
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index fbe09fa5e54ab1..aeeb970433fc4a 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -278,6 +278,7 @@
{ include: [ "<__chrono/formatter.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/hh_mm_ss.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/high_resolution_clock.h>", "private", "<chrono>", "public" ] },
+ { include: [ "<__chrono/leap_second.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/literals.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/month.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/month_weekday.h>", "private", "<chrono>", "public" ] },
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index e72136a58c0b1b..4f106d0a6c7e4a 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1141,6 +1141,7 @@ module std_private_chrono_high_resolution_clock [system] {
export std_private_chrono_steady_clock
export std_private_chrono_system_clock
}
+module std_private_chrono_leap_second [system] { header "__chrono/leap_second.h" }
module std_private_chrono_literals [system] { header "__chrono/literals.h" }
module std_private_chrono_month [system] { header "__chrono/month.h" }
module std_private_chrono_month_weekday [system] { header "__chrono/month_weekday.h" }
diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc
index 109023a3abc25f..2c0bd3f98a67d7 100644
--- a/libcxx/modules/std/chrono.inc
+++ b/libcxx/modules/std/chrono.inc
@@ -208,10 +208,7 @@ export namespace std {
using std::chrono::reload_tzdb;
using std::chrono::remote_version;
-# endif // !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) &&
- // !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-
-# if 0
+# if 0
// [time.zone.exception], exception classes
using std::chrono::ambiguous_local_time;
using std::chrono::nonexistent_local_time;
@@ -221,11 +218,11 @@ export namespace std {
// [time.zone.timezone], class time_zone
using std::chrono::choose;
-# endif
-# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
+# endif // if 0
+
using std::chrono::time_zone;
-# endif
-# if 0
+
+# if 0
// [time.zone.zonedtraits], class template zoned_traits
using std::chrono::zoned_traits;
@@ -234,22 +231,23 @@ export namespace std {
using std::chrono::zoned_time;
using std::chrono::zoned_seconds;
+# endif // if 0
// [time.zone.leap], leap second support
using std::chrono::leap_second;
-# endif
-# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
// [time.zone.link], class time_zone_link
using std::chrono::time_zone_link;
-# endif
-# if 0
+# if 0
// [time.format], formatting
using std::chrono::local_time_format;
-# endif
-#endif // _LIBCPP_ENABLE_EXPERIMENTAL
- } // namespace chrono
+# endif
+# endif // _LIBCPP_ENABLE_EXPERIMENTAL
+#endif // !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) &&
+ // !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+
+ } // namespace chrono
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
using std::formatter;
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index cc6954a7bac37e..428770cba7138f 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -336,6 +336,7 @@ endif()
if (LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_TIME_ZONE_DATABASE)
list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
+ include/tzdb/leap_second_private.h
include/tzdb/time_zone_link_private.h
include/tzdb/time_zone_private.h
include/tzdb/types_private.h
diff --git a/libcxx/src/include/tzdb/leap_second_private.h b/libcxx/src/include/tzdb/leap_second_private.h
new file mode 100644
index 00000000000000..7a811ab1975942
--- /dev/null
+++ b/libcxx/src/include/tzdb/leap_second_private.h
@@ -0,0 +1,27 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
+
+#ifndef _LIBCPP_SRC_INCLUDE_TZDB_LEAP_SECOND_PRIVATE_H
+#define _LIBCPP_SRC_INCLUDE_TZDB_LEAP_SECOND_PRIVATE_H
+
+#include <chrono>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace chrono {
+
+struct leap_second::__constructor_tag {};
+
+} // namespace chrono
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_SRC_INCLUDE_TZDB_LEAP_SECOND_PRIVATE_H
diff --git a/libcxx/src/tzdb.cpp b/libcxx/src/tzdb.cpp
index 2bb801e48694ee..f1b72d57d7d5c7 100644
--- a/libcxx/src/tzdb.cpp
+++ b/libcxx/src/tzdb.cpp
@@ -15,6 +15,7 @@
#include <stdexcept>
#include <string>
+#include "include/tzdb/leap_second_private.h"
#include "include/tzdb/time_zone_link_private.h"
#include "include/tzdb/time_zone_private.h"
#include "include/tzdb/types_private.h"
@@ -603,6 +604,36 @@ static void __parse_tzdata(tzdb& __db, __tz::__rules_storage_type& __rules, istr
}
}
+static void __parse_leap_seconds(vector<leap_second>& __leap_seconds, istream&& __input) {
+ // The file stores dates since 1 January 1900, 00:00:00, we want
+ // seconds since 1 January 1970.
+ constexpr auto __offset = sys_days{1970y / January / 1} - sys_days{1900y / January / 1};
+
+ while (true) {
+ switch (__input.peek()) {
+ case istream::traits_type::eof():
+ return;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ __input.get();
+ continue;
+
+ case '#':
+ chrono::__skip_line(__input);
+ continue;
+ }
+
+ sys_seconds __date = sys_seconds{seconds{chrono::__parse_integral(__input, false)}} - __offset;
+ chrono::__skip_mandatory_whitespace(__input);
+ seconds __value{chrono::__parse_integral(__input, false)};
+ chrono::__skip_line(__input);
+
+ __leap_seconds.emplace_back(leap_second::__constructor_tag{}, __date, __value);
+ }
+}
+
void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
filesystem::path __root = chrono::__libcpp_tzdb_directory();
ifstream __tzdata{__root / "tzdata.zi"};
@@ -612,6 +643,16 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
std::ranges::sort(__tzdb.zones);
std::ranges::sort(__tzdb.links);
std::ranges::sort(__rules, {}, [](const auto& p) { return p.first; });
+
+ // There are two files with the leap second information
+ // - leapseconds as specified by zic
+ // - leap-seconds.list the source data
+ // The latter is much easier to parse, it seems Howard shares that
+ // opinion.
+ chrono::__parse_leap_seconds(__tzdb.leap_seconds, ifstream{__root / "leap-seconds.list"});
+ // Note the input is sorted, but that does not seem to be are
+ // requirement, it is a requirement in the Standard.
+ std::ranges::sort(__tzdb.leap_seconds);
}
//===----------------------------------------------------------------------===//
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp
index 8019824046c47f..c868832ea74ada 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp
@@ -26,6 +26,7 @@
// These types have "private" constructors.
extern std::chrono::time_zone tz;
extern std::chrono::time_zone_link link;
+extern std::chrono::leap_second leap;
void test() {
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
@@ -51,4 +52,9 @@ void test() {
operator==(link, link);
operator<=>(link, link);
}
+
+ {
+ leap.date();
+ leap.value();
+ }
}
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
index e9b27559497b7e..4d26b46a89c91b 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
@@ -23,6 +23,7 @@
// These types have "private" constructors.
extern std::chrono::time_zone tz;
extern std::chrono::time_zone_link link;
+extern std::chrono::leap_second leap;
void test() {
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
@@ -51,4 +52,9 @@ void test() {
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
operator<=>(link, link);
}
+
+ {
+ leap.date(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ leap.value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
}
diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp
new file mode 100644
index 00000000000000..d7303890132824
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// Tests the IANA database leap seconds parsing and operations.
+// This is not part of the public tzdb interface.
+
+#include <cassert>
+#include <chrono>
+#include <fstream>
+#include <string>
+#include <string_view>
+
+#include "assert_macros.h"
+#include "concat_macros.h"
+#include "filesystem_test_helper.h"
+#include "test_tzdb.h"
+
+scoped_test_env env;
+[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
+const std::filesystem::path tzdata = env.create_file("zoneinfo/tzdata.zi");
+const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leap-seconds.list");
+
+std::string_view std::chrono::__libcpp_tzdb_directory() {
+ static std::string result = dir.string();
+ return result;
+}
+
+void write(std::string_view input) {
+ static int version = 0;
+
+ std::ofstream f{tzdata};
+ f << "# version " << version++ << '\n';
+ std::ofstream{leap_seconds}.write(input.data(), input.size());
+}
+
+static const std::chrono::tzdb& parse(std::string_view input) {
+ write(input);
+ return std::chrono::reload_tzdb();
+}
+
+static void test_exception(std::string_view input, [[maybe_unused]] std::string_view what) {
+ write(input);
+
+ TEST_VALIDATE_EXCEPTION(
+ std::runtime_error,
+ [&]([[maybe_unused]] const std::runtime_error& e) {
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
+ },
+ TEST_IGNORE_NODISCARD std::chrono::reload_tzdb());
+}
+
+static void test_invalid() {
+ test_exception("0", "corrupt tzdb: expected a non-zero digit");
+
+ test_exception("1", "corrupt tzdb: expected whitespace");
+
+ test_exception("1 ", "corrupt tzdb: expected a non-zero digit");
+}
+
+static void test_leap_seconds() {
+ using namespace std::chrono;
+
+ const tzdb& result = parse(
+ R"(
+2272060800 10 # 1 Jan 1972
+2287785600 11 # 1 Jul 1972
+2303683200 12 # 1 Jan 1973
+)");
+
+ assert(result.leap_seconds.size() == 3);
+
+ assert(result.leap_seconds[0].date() == sys_seconds{sys_days{1972y / January / 1}});
+ assert(result.leap_seconds[0].value() == 10s);
+
+ assert(result.leap_seconds[1].date() == sys_seconds{sys_days{1972y / July / 1}});
+ assert(result.leap_seconds[1].value() == 11s);
+
+ assert(result.leap_seconds[2].date() == sys_seconds{sys_days{1973y / January / 1}});
+ assert(result.leap_seconds[2].value() == 12s);
+}
+
+int main(int, const char**) {
+ test_invalid();
+ test_leap_seconds();
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.db/time.zone.db.access/get_tzdb.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.db/time.zone.db.access/get_tzdb.pass.cpp
index b6204c615d965e..470a722d0b69c6 100644
--- a/libcxx/test/std/time/time.zone/time.zone.db/time.zone.db.access/get_tzdb.pass.cpp
+++ b/libcxx/test/std/time/time.zone/time.zone.db/time.zone.db.access/get_tzdb.pass.cpp
@@ -35,5 +35,8 @@ int main(int, const char**) {
assert(std::ranges::is_sorted(db.links));
assert(std::ranges::adjacent_find(db.links) == db.links.end()); // is unique?
+ assert(!db.leap_seconds.empty());
+ assert(std::ranges::is_sorted(db.leap_seconds));
+
return 0;
}
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp
new file mode 100644
index 00000000000000..de7e9235ff02e5
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class leap_second
+// {
+// leap_second& operator=(const leap_second&) = default;
+//
+// ...
+// };
+
+#include <chrono>
+#include <type_traits>
+#include <cassert>
+
+// Add the include path required by test_chrono_leap_second.h when using libc++.
+// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %S/../../../../../src/include
+#include "test_chrono_leap_second.h"
+
+constexpr bool test() {
+ std::chrono::leap_second a =
+ test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{0}}, std::chrono::seconds{1});
+ std::chrono::leap_second b =
+ test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{10}}, std::chrono::seconds{15});
+
+ // operator== only compares the date member.
+ assert(a.date() != b.date());
+ assert(a.value() != b.value());
+
+ b = a;
+ assert(a.date() == b.date());
+ assert(a.value() == b.value());
+
+ return true;
+}
+
+int main(int, const char**) {
+ static_assert(std::is_copy_assignable_v<std::chrono::leap_second>);
+
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp
new file mode 100644
index 00000000000000..1eab5d613734a9
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class leap_second
+// {
+// leap_second(const leap_second&) = default;
+//
+// ...
+// };
+
+#include <chrono>
+#include <concepts>
+#include <cassert>
+
+// Add the include path required by test_chrono_leap_second.h when using libc++.
+// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %S/../../../../../src/include
+#include "test_chrono_leap_second.h"
+
+constexpr bool test() {
+ std::chrono::leap_second a =
+ test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{0}}, std::chrono::seconds{1});
+ std::chrono::leap_second b(a);
+
+ // operator== only compares the date member.
+ assert(a.date() == b.date());
+ assert(a.value() == b.value());
+
+ return true;
+}
+
+int main(int, const char**) {
+ static_assert(std::copy_constructible<std::chrono::leap_second>);
+
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp
new file mode 100644
index 00000000000000..e119dbc9a67ba4
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class leap_second;
+
+// constexpr sys_seconds date() const noexcept;
+
+#include <cassert>
+#include <chrono>
+
+#include "test_macros.h"
+
+// Add the include path required by test_chrono_leap_second.h when using libc++.
+// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %S/../../../../../../src/include
+#include "test_chrono_leap_second.h"
+
+constexpr bool test(const std::chrono::leap_second leap_second, std::chrono::sys_seconds expected) {
+ std::same_as<std::chrono::sys_seconds> auto date = leap_second.date();
+ assert(date == expected);
+ static_assert(noexcept(leap_second.date()));
+
+ return true;
+}
+
+int main(int, const char**) {
+ const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
+ assert(!tzdb.leap_seconds.empty());
+ test(tzdb.leap_seconds[0], tzdb.leap_seconds[0].date());
+
+ static_assert(
+ test(test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{0}}, std::chrono::seconds{1}),
+ std::chrono::sys_seconds{std::chrono::seconds{0}}));
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp
new file mode 100644
index 00000000000000..27f78eedb9cc10
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class leap_second;
+
+// constexpr seconds value() const noexcept;
+
+#include <cassert>
+#include <chrono>
+
+#include "test_macros.h"
+
+// Add the include path required by test_chrono_leap_second.h when using libc++.
+// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %S/../../../../../../src/include
+#include "test_chrono_leap_second.h"
+
+constexpr bool test(const std::chrono::leap_second leap_second, std::chrono::seconds expected) {
+ std::same_as<std::chrono::seconds> auto value = leap_second.value();
+ assert(value == expected);
+ static_assert(noexcept(leap_second.value()));
+
+ return true;
+}
+
+int main(int, const char**) {
+ const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
+ assert(!tzdb.leap_seconds.empty());
+ test(tzdb.leap_seconds[0], tzdb.leap_seconds[0].value());
+
+ static_assert(
+ test(test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{0}}, std::chrono::seconds{1}),
+ std::chrono::seconds{1}));
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp
new file mode 100644
index 00000000000000..42dbbf139ddd3f
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class leap_second;
+
+//constexpr bool operator==(const leap_second& x, const leap_second& y); // C++20
+//constexpr strong_ordering operator<=>(const leap_second& x, const leap_second& y);
+//
+//template<class Duration>
+// constexpr bool operator==(const leap_second& x, const sys_time<Duration>& y);
+//template<class Duration>
+// constexpr bool operator< (const leap_second& x, const sys_time<Duration>& y);
+//template<class Duration>
+// constexpr bool operator< (const sys_time<Duration>& x, const leap_second& y);
+//template<class Duration>
+// constexpr bool operator> (const leap_second& x, const sys_time<Duration>& y);
+//template<class Duration>
+// constexpr bool operator> (const sys_time<Duration>& x, const leap_second& y);
+//template<class Duration>
+// constexpr bool operator<=(const leap_second& x, const sys_time<Duration>& y);
+//template<class Duration>
+// constexpr bool operator<=(const sys_time<Duration>& x, const leap_second& y);
+//template<class Duration>
+// constexpr bool operator>=(const leap_second& x, const sys_time<Duration>& y);
+//template<class Duration>
+// constexpr bool operator>=(const sys_time<Duration>& x, const leap_second& y);
+//template<class Duration>
+// requires three_way_comparable_with<sys_seconds, sys_time<Duration>>
+// constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y);
+
+#include <cassert>
+#include <chrono>
+
+#include "test_macros.h"
+#include "test_comparisons.h"
+
+// Add the include path required by test_chrono_leap_second.h when using libc++.
+// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %S/../../../../../../src/include
+#include "test_chrono_leap_second.h"
+
+constexpr bool test(const std::chrono::leap_second lhs, const std::chrono::leap_second rhs) {
+ AssertOrderReturn<std::strong_ordering, std::chrono::leap_second>();
+ assert(testOrder(lhs, rhs, std::strong_ordering::less));
+
+ AssertOrderReturn<std::strong_ordering, std::chrono::leap_second, std::chrono::sys_seconds>();
+ assert(testOrder(lhs, rhs.date(), std::strong_ordering::less));
+
+ AssertOrderReturn<std::strong_ordering, std::chrono::sys_seconds, std::chrono::leap_second>();
+ assert(testOrder(lhs.date(), rhs, std::strong_ordering::less));
+
+ return true;
+}
+
+int main(int, const char**) {
+ const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
+ assert(tzdb.leap_seconds.size() > 2);
+ test(tzdb.leap_seconds[0], tzdb.leap_seconds[1]);
+
+ static_assert(
+ test(test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{0}}, std::chrono::seconds{1}),
+ test_leap_second_create(std::chrono::sys_seconds{std::chrono::seconds{1}}, std::chrono::seconds{2})));
+
+ return 0;
+}
diff --git a/libcxx/test/support/test_chrono_leap_second.h b/libcxx/test/support/test_chrono_leap_second.h
new file mode 100644
index 00000000000000..253eac316c4246
--- /dev/null
+++ b/libcxx/test/support/test_chrono_leap_second.h
@@ -0,0 +1,53 @@
+// -*- 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 SUPPORT_TEST_CHRONO_LEAP_SECOND_HPP
+#define SUPPORT_TEST_CHRONO_LEAP_SECOND_HPP
+
+/**
+ * @file Helper functions to create a @ref std::chrono::leap_second.
+ *
+ * Since the standard doesn't specify how a @ref std::chrono::leap_second is
+ * constructed this is implementation defined. To make the public API tests of
+ * the class generic this header defines helper functions to create the
+ * required object.
+ *
+ * @note This requires every standard library implementation to write their own
+ * helper function. Vendors are encouraged to create a pull request at
+ * https://github.com/llvm/llvm-project so their specific implementation can be
+ * part of this file.
+ */
+
+#include "test_macros.h"
+
+#if TEST_STD_VER < 20
+# error "The format header requires at least C++20"
+#endif
+
+#include <chrono>
+
+#ifdef _LIBCPP_VERSION
+
+// In order to find this include the calling test needs to provide this path in
+// the search path. Typically this looks like:
+// REMOVE_THIS_PREFIX__ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %S/../../../../../../src/include
+// where the number of `../` sequences depends on the subdirectory level of the
+// test.
+# include "tzdb/leap_second_private.h" // Header in the dylib
+
+inline constexpr std::chrono::leap_second
+test_leap_second_create(const std::chrono::sys_seconds& date, const std::chrono::seconds& value) {
+ return std::chrono::leap_second{std::chrono::leap_second::__constructor_tag{}, date, value};
+}
+
+#else // _LIBCPP_VERSION
+# error "Please create a vendor specific version of the test functions and file a review at https://reviews.llvm.org/"
+#endif // _LIBCPP_VERSION
+
+#endif // SUPPORT_TEST_CHRONO_LEAP_SECOND_HPP
More information about the llvm-branch-commits
mailing list