This change allows the hardcoded list of leap seconds in <chrono> to be
used even when the program is executing after the hardcoded expiry date
in that header.
For times after the hardcoded expiry, the inline __get_leap_second_info
function calls a new library function which compares the number of
hardcoded leap seconds in the header with the number of leap seconds
defined in the tzdata leapseconds file (usually provided by the OS).
There are three leap second lists that are relevant here. The first is
the hardcoded list (and its expiry time) in the <chrono> header. That is
fixed when the user code is compiled, and might be out of date by the
time the application runs. The second list (and its expiry time) is
hardcoded in tzdb.cc in the libstdc++.so library. If the application
uses a newer libstdc++.so at runtime than the <chrono> header used at
compile time, we can still avoid going to the filesystem for dates
within the expiry time of the list in libstdc++.so. The third list is
the most up-to-date one which is read from the leapseconds file.
The code added by this commit tries to avoid reading the file when
possible (because that's slower than using the in-memory lists), and if
it does have to go to the file system, it tries to avoid doing so again
next time the leap seconds are needed.
libstdc++-v3/ChangeLog:
PR libstdc++/123165
* acinclude.m4 (libtool_VERSION): Bump version.
* config/abi/pre/gnu.ver (GLIBCXX_3.4.36): Add new symbol
version and export new symbol.
* configure: Regenerate.
* include/std/chrono (__detail::__recent_leap_second_info):
Declare new function and make it a friend of varous classes.
(leap_second): Make private constructor constexpr. Remove friend
declaration for get_leap_second_info.
(__detail::__get_leap_second_info): Use new function for times
past the hardcoded expiry.
* src/c++20/tzdb.cc (tzdb_list::_Node::fixed_leaps): Move array
of leap seconds here from _S_read_leap_seconds.
(fixed_expiry, num_leap_seconds): New globals.
(__detail::__recent_leap_second_info): Define new function.
(tzdb_list::_Node::_S_read_leap_seconds): Populate vector from
_Node::fixed_leaps. Rename bool variable to clarify meaning.
(tzdb_list::_Node::_S_replace_head): Update num_leap_seconds
when updating the tzdb_list.
* testsuite/util/testsuite_abi.cc: Update known_versions and
latestp.
* testsuite/std/time/clock/utc/leap_second_info-2.cc: New test.
Co-authored-by: Tomasz Kamiński <[email protected]>
Signed-off-by: Tomasz Kamiński <[email protected]>
---
Tested x86_64-linux.
libstdc++-v3/acinclude.m4 | 2 +-
libstdc++-v3/config/abi/pre/gnu.ver | 7 +
libstdc++-v3/configure | 2 +-
libstdc++-v3/include/std/chrono | 110 ++++-----
libstdc++-v3/src/c++20/tzdb.cc | 212 ++++++++++++++----
.../std/time/clock/utc/leap_second_info-2.cc | 93 ++++++++
libstdc++-v3/testsuite/util/testsuite_abi.cc | 3 +-
7 files changed, 328 insertions(+), 101 deletions(-)
create mode 100644
libstdc++-v3/testsuite/std/time/clock/utc/leap_second_info-2.cc
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 8dc9e17b214c..3a4b11a98a28 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -4085,7 +4085,7 @@ changequote([,])dnl
fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:35:0
+libtool_VERSION=6:36:0
# Everything parsed; figure out what files and settings to use.
case $enable_symvers in
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver
b/libstdc++-v3/config/abi/pre/gnu.ver
index bd4da6418295..06892cd2d18b 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2623,6 +2623,13 @@ GLIBCXX_3.4.35 {
} GLIBCXX_3.4.34;
+# GCC 17.1.0
+GLIBCXX_3.4.36 {
+
+ _ZNSt6chrono8__detail25__recent_leap_second_infoERNS_16leap_second_infoEj;
+
+} GLIBCXX_3.4.35;
+
# Symbols in the support library (libsupc++) have their own tag.
CXXABI_1.3 {
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 6713e4504b1c..013c388b9c2f 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -51418,7 +51418,7 @@ $as_echo "$as_me: WARNING: === Symbol versioning will
be disabled." >&2;}
fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:35:0
+libtool_VERSION=6:36:0
# Everything parsed; figure out what files and settings to use.
case $enable_symvers in
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 674f867dcdc7..692fd6025e7d 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -131,6 +131,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
leap_second_info
get_leap_second_info(const utc_time<_Duration>& __ut);
+ /// @cond undocumented
+ namespace __detail
+ {
+ bool __recent_leap_second_info(leap_second_info&, unsigned);
+ }
+ /// @endcond
+
/** A clock that measures Universal Coordinated Time (UTC).
*
* The epoch is 1970-01-01 00:00:00.
@@ -2818,6 +2825,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
friend class leap_second;
friend struct time_zone::_Impl;
friend class time_zone_link;
+
+ friend bool
+ __detail::__recent_leap_second_info(leap_second_info&, unsigned);
};
class time_zone_link
@@ -2943,16 +2953,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __x.date() <=> __y; }
private:
- explicit leap_second(seconds::rep __s) : _M_s(__s) { }
+ constexpr explicit leap_second(seconds::rep __s) : _M_s(__s) { }
friend struct tzdb_list::_Node;
friend const tzdb& reload_tzdb();
- template<typename _Duration>
- friend leap_second_info
- get_leap_second_info(const utc_time<_Duration>&);
-
seconds _M_s; // == date().time_since_epoch() * value().count()
};
@@ -3217,6 +3223,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace __detail
{
+ // This function is inline to support fast conversions between utc_time
+ // and sys_time when possible, without requiring a chrono::tzdb object
+ // to be constructed.
inline leap_second_info
__get_leap_second_info(sys_seconds __ss, bool __is_utc)
{
@@ -3252,65 +3261,56 @@ namespace __detail
1435708800, // 1 Jul 2015
1483228800, // 1 Jan 2017
};
+
+ // The default result for times after the last leap year.
+ constexpr leap_second_info __after_last{
+ .is_leap_second = false,
+ .elapsed = seconds(std::size(__leaps))
+ };
+
// The list above is known to be valid until (at least) this date
// and only contains positive leap seconds.
constexpr sys_seconds __expires(1798416000s); // 2026-12-28 00:00:00 UTC
-#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
if (__ss > __expires)
{
- // Use updated leap_seconds from tzdb.
- size_t __n = std::size(__leaps);
+#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI // use chrono::tzdb
+ // Call into the library because it might have knowledge of new
+ // leap seconds loaded at runtime from the tzdata files.
- auto __db = get_tzdb_list().begin();
- auto __first = __db->leap_seconds.begin() + __n;
- auto __last = __db->leap_seconds.end();
- auto __pos = std::upper_bound(__first, __last, __ss);
- seconds __elapsed(__n);
- for (auto __i = __first; __i != __pos; ++__i)
- __elapsed += __i->value();
-
- if (__is_utc)
- {
- // Convert utc_time to sys_time:
- __ss -= __elapsed;
- // See if that sys_time is before (or during) previous leap sec:
- if (__pos != __first && __ss < __pos[-1])
- {
- if ((__ss + 1s) >= __pos[-1])
- return {true, __elapsed};
- __elapsed -= __pos[-1].value();
- }
- }
- return {false, __elapsed};
- }
- else
+ // We misuse leap_second_info here to pass {bool, seconds} inputs:
+ leap_second_info __info{ .is_leap_second = __is_utc,
+ .elapsed = __ss.time_since_epoch() };
+ // If this returns true, then __info holds the output result:
+ if (__detail::__recent_leap_second_info(__info, std::size(__leaps)))
+ return __info;
#endif
- {
- seconds::rep __s = __ss.time_since_epoch().count();
- const seconds::rep* __first = std::begin(__leaps);
- const seconds::rep* __last = std::end(__leaps);
-
- // Don't bother searching the list if we're after the last one.
- if (__s > (__last[-1] + (__last - __first) + 1))
- return { false, seconds(__last - __first) };
-
- auto __pos = std::upper_bound(__first, __last, __s);
- seconds __elapsed{__pos - __first};
- if (__is_utc)
- {
- // Convert utc_time to sys_time:
- __s -= __elapsed.count();
- // See if that sys_time is before (or during) previous leap sec:
- if (__pos != __first && __s < __pos[-1])
- {
- if ((__s + 1) >= __pos[-1])
- return {true, __elapsed};
- --__elapsed;
- }
- }
- return {false, __elapsed};
+ return __after_last;
}
+
+ seconds::rep __s = __ss.time_since_epoch().count();
+ const seconds::rep* __first = std::begin(__leaps);
+ const seconds::rep* __last = std::end(__leaps);
+
+ // Don't bother searching the list if we're after the last one.
+ if (__s > (__last[-1] + (__last - __first) + 1))
+ return __after_last;
+
+ auto __pos = std::upper_bound(__first, __last, __s);
+ seconds __elapsed{__pos - __first};
+ if (__is_utc)
+ {
+ // Convert utc_time to sys_time:
+ __s -= __elapsed.count();
+ // See if that sys_time is before (or during) previous leap sec:
+ if (__pos != __first && __s < __pos[-1])
+ {
+ if ((__s + 1) >= __pos[-1])
+ return {true, __elapsed};
+ --__elapsed;
+ }
+ }
+ return {false, __elapsed};
}
} // namespace __detail
diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
index b0fbfc46a6d3..587e88bc0dd5 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -36,6 +36,7 @@
#include <memory> // atomic<shared_ptr<T>>
#include <mutex> // mutex
#include <iomanip> // quoted
+#include <span>
#if defined __GTHREADS && ! defined _GLIBCXX_HAS_GTHREADS
# include <ext/concurrence.h> // __gnu_cxx::__mutex
#endif
@@ -196,6 +197,9 @@ namespace std::chrono
static const tzdb& _S_replace_head(shared_ptr<_Node>, shared_ptr<_Node>);
static pair<vector<leap_second>, bool> _S_read_leap_seconds();
+
+ // This is here because _Node is a friend so can call private constructor.
+ static const leap_second fixed_leaps[];
};
// Implementation of the private constructor used for the singleton object.
@@ -1251,56 +1255,168 @@ namespace std::chrono
}
#endif // TZDB_DISABLED
+// These are the same values as the array in the <chrono> header, but might
+// contain additional leap seconds if the libstdc++.so used at runtime is
+// newer than the <chrono> header used to compile parts of the application.
+constexpr leap_second tzdb_list::_Node::fixed_leaps[] {
+#define LS leap_second
+ LS( 78796800), // 1 Jul 1972
+ LS( 94694400), // 1 Jan 1973
+ LS( 126230400), // 1 Jan 1974
+ LS( 157766400), // 1 Jan 1975
+ LS( 189302400), // 1 Jan 1976
+ LS( 220924800), // 1 Jan 1977
+ LS( 252460800), // 1 Jan 1978
+ LS( 283996800), // 1 Jan 1979
+ LS( 315532800), // 1 Jan 1980
+ LS( 362793600), // 1 Jul 1981
+ LS( 394329600), // 1 Jul 1982
+ LS( 425865600), // 1 Jul 1983
+ LS( 489024000), // 1 Jul 1985
+ LS( 567993600), // 1 Jan 1988
+ LS( 631152000), // 1 Jan 1990
+ LS( 662688000), // 1 Jan 1991
+ LS( 709948800), // 1 Jul 1992
+ LS( 741484800), // 1 Jul 1993
+ LS( 773020800), // 1 Jul 1994
+ LS( 820454400), // 1 Jan 1996
+ LS( 867715200), // 1 Jul 1997
+ LS( 915148800), // 1 Jan 1999
+ LS(1136073600), // 1 Jan 2006
+ LS(1230768000), // 1 Jan 2009
+ LS(1341100800), // 1 Jul 2012
+ LS(1435708800), // 1 Jul 2015
+ LS(1483228800), // 1 Jan 2017
+ // If new leap seconds get defined they should be added here.
+ // Negative leap seconds are represented as -1 * timestamp.
+#undef LS
+};
+
+namespace
+{
+ // The expiry date corresponding to the list above.
+ // tzdata 2026a leapseconds list expires at 2026-12-28 00:00:00 UTC
+ constexpr seconds fixed_expiry{1798416000u};
+
+ // This holds the most up-to-date number of leap seconds known at runtime.
+ // Initially zero, updated when _S_read_leap_seconds() is called.
+ constinit atomic<unsigned> num_leap_seconds{0};
+}
+
+ namespace __detail
+ {
+ // Called by chrono::__detail::__get_leap_second_info in <chrono>
+ // to get leap_second_info for times after the expiry date in the header.
+ // The caller provides the time being queried in `info.elapsed` and
+ // whether that is a UTC time in `info.is_leap_second`.
+ // If it returns true, this function did the lookup and updated `info`.
+ // If this returns false, it means the hardcoded list of leap seconds
+ // in the header should be used for the lookup.
+ bool
+ __recent_leap_second_info(leap_second_info& info,
+ unsigned num_positive_leaps)
+ {
+ // Extract the input args from info:
+ const auto [is_utc, secs] = info;
+ // And then reuse info for the output result:
+ info.is_leap_second = false;
+ info.elapsed = seconds(num_positive_leaps);
+
+ auto update_info = [&](span<const leap_second> leaps)
+ {
+ if (leaps.size() == num_positive_leaps)
+ return false; // No new leap seconds, use the array in the header.
+
+ // info.elapsed already contains the first N leap seconds,
+ // so we only search the end of the span.
+ auto first = leaps.begin() + num_positive_leaps;
+ auto pos = std::upper_bound(first, leaps.end(), sys_seconds(secs));
+ for (auto i = first; i != pos; ++i)
+ info.elapsed += i->value();
+
+ if (is_utc)
+ {
+ // This should never happen, but check it so that pos[-1] is valid:
+ if (num_positive_leaps == 0) [[unlikely]]
+ return false;
+
+ // Convert utc_time to sys_time:
+ sys_seconds ss(secs - info.elapsed);
+ // See if that sys_time is before (or during) previous leap sec:
+ if (ss < pos[-1])
+ {
+ if ((ss + 1s) >= pos[-1])
+ info.is_leap_second = true;
+ else
+ info.elapsed -= pos[-1].value();
+ }
+ }
+ return true;
+ };
+
+ using _Node = tzdb_list::_Node;
+
+ // If the caller was compiled using an older GCC with an older expiry
+ // time in the header than the `fixed_expiry` defined above, we might
+ // be able to answer the query easily using the static `fixed_leaps`.
+ if (secs <= fixed_expiry)
+ return update_info(_Node::fixed_leaps);
+
+ constexpr auto num_fixed_leaps = std::size(_Node::fixed_leaps);
+
+ auto num_leaps = num_leap_seconds.load(memory_order::relaxed);
+ if (num_leaps == num_fixed_leaps)
+ // A leapseconds file has been read and has no new leap seconds:
+ return update_info(_Node::fixed_leaps);
+ else if (num_leaps != 0)
+ // The tzdb_list has been initialized and contains a tzdb object
+ // with new leap seconds, which we want to use here.
+ // The relaxed load above does not synchronize with anything, so to
+ // ensure that the get_tzdb_list() below will see a tzdb object set
+ // by _S_replace_head, we load num_leap_seconds again with acquire
+ // ordering:
+ (void) num_leap_seconds.load(memory_order::acquire);
+ else
+ {
+ // The tzdb_list has not been initialized yet, so we don't know
+ // the correct number of leap seconds.
+ // We use _S_read_leap_seconds() to read the leapseconds file.
+ // If that tells us there are no new leapseconds, we don't need
+ // to parse all of tzdata.zi and initialize a whole tzdb object.
+ if (_Node::_S_read_leap_seconds().first.size() == num_fixed_leaps)
+ {
+ // There are no new leap seconds. remember that so that the next
+ // call to this function can just use fixed_leaps.
+ num_leap_seconds.compare_exchange_strong(num_leaps,
+ num_fixed_leaps,
+ memory_order::relaxed);
+ return update_info(_Node::fixed_leaps);
+ }
+ // else there are new leap seconds. We init tzdb_list so that the
+ // new leap seconds are persisted in a tzdb object.
+ }
+
+ // Use updated leap_seconds from tzdb.
+ return update_info(get_tzdb_list().begin()->leap_seconds);
+ }
+ }
+
// Return leap_second values, and a bool indicating whether the values are
// current (true), or potentially out of date (false).
pair<vector<leap_second>, bool>
tzdb_list::_Node::_S_read_leap_seconds()
{
- // This list is valid until at least 2026-12-28 00:00:00 UTC.
- constexpr auto expires = sys_days{2026y/12/28};
- vector<leap_second> leaps
- {
- (leap_second) 78796800, // 1 Jul 1972
- (leap_second) 94694400, // 1 Jan 1973
- (leap_second) 126230400, // 1 Jan 1974
- (leap_second) 157766400, // 1 Jan 1975
- (leap_second) 189302400, // 1 Jan 1976
- (leap_second) 220924800, // 1 Jan 1977
- (leap_second) 252460800, // 1 Jan 1978
- (leap_second) 283996800, // 1 Jan 1979
- (leap_second) 315532800, // 1 Jan 1980
- (leap_second) 362793600, // 1 Jul 1981
- (leap_second) 394329600, // 1 Jul 1982
- (leap_second) 425865600, // 1 Jul 1983
- (leap_second) 489024000, // 1 Jul 1985
- (leap_second) 567993600, // 1 Jan 1988
- (leap_second) 631152000, // 1 Jan 1990
- (leap_second) 662688000, // 1 Jan 1991
- (leap_second) 709948800, // 1 Jul 1992
- (leap_second) 741484800, // 1 Jul 1993
- (leap_second) 773020800, // 1 Jul 1994
- (leap_second) 820454400, // 1 Jan 1996
- (leap_second) 867715200, // 1 Jul 1997
- (leap_second) 915148800, // 1 Jan 1999
- (leap_second)1136073600, // 1 Jan 2006
- (leap_second)1230768000, // 1 Jan 2009
- (leap_second)1341100800, // 1 Jul 2012
- (leap_second)1435708800, // 1 Jul 2015
- (leap_second)1483228800, // 1 Jan 2017
- };
+ // Populate the vector with the leap seconds we already know about:
+ vector<leap_second> leaps(fixed_leaps, std::end(fixed_leaps));
-#if 0
- // This optimization isn't valid if the file has additional leap seconds
- // defined since the library was compiled, but the system clock has been
- // set to a time before the hardcoded expiration date.
- if (system_clock::now() < expires)
- return {std::move(leaps), true};
-#endif
+ bool read_leaps_file = false;
#ifndef TZDB_DISABLED
if (ifstream ls{zoneinfo_file(leaps_file)})
{
- auto exp_year = year_month_day(expires).year();
+ constexpr year exp_year
+ = year_month_day(sys_days(duration_cast<days>(fixed_expiry))).year();
+
std::string s, w;
s.reserve(80); // Avoid later reallocations.
while (std::getline(ls, s))
@@ -1309,6 +1425,7 @@ namespace std::chrono
if (!s.starts_with("Leap"))
continue;
+
istringstream li(std::move(s));
li.exceptions(ios::failbit);
li.ignore(4);
@@ -1339,12 +1456,14 @@ namespace std::chrono
leaps.push_back(ls);
}
}
- s = std::move(li).str(); // return storage to s
+ s = std::move(li).str(); // give allocated storage back to s
}
- return {std::move(leaps), true};
+
+ read_leaps_file = true;
}
#endif
- return {std::move(leaps), false};
+
+ return {std::move(leaps), read_leaps_file};
}
#ifndef TZDB_DISABLED
@@ -1413,6 +1532,13 @@ namespace std::chrono
_S_head_owner = std::move(new_head);
#endif
_S_cache_list_head(new_head_ptr);
+
+ // This allows __recent_leap_second_info() to know that it can use
+ // get_tzdb_list()->begin()->leap_seconds to get new leap seconds.
+ // The release op here synchronizes with the acquire op there.
+ num_leap_seconds.store(new_head_ptr->db.leap_seconds.size(),
+ memory_order::release);
+
return new_head_ptr->db;
}
diff --git a/libstdc++-v3/testsuite/std/time/clock/utc/leap_second_info-2.cc
b/libstdc++-v3/testsuite/std/time/clock/utc/leap_second_info-2.cc
new file mode 100644
index 000000000000..c6f07acbda60
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/clock/utc/leap_second_info-2.cc
@@ -0,0 +1,93 @@
+// { dg-do run { target c++20 } }
+// { dg-require-effective-target tzdb }
+// { dg-require-effective-target cxx11_abi }
+// { dg-xfail-run-if "no weak override on AIX" { powerpc-ibm-aix* } }
+
+#include <chrono>
+#include <fstream>
+#include <testsuite_hooks.h>
+
+using namespace std::chrono_literals;
+
+static bool override_used = false;
+
+namespace __gnu_cxx
+{
+ const char* zoneinfo_dir_override() {
+ override_used = true;
+ return "./";
+ }
+}
+
+void
+test_known_leaps()
+{
+ // Test some values within the list of known leap seconds.
+ auto s = std::chrono::utc_seconds(-1s);
+ auto lsi = get_leap_second_info(s);
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == 0s );
+
+ s = std::chrono::utc_seconds(126230402s); // 1 Jan 1974
+ lsi = get_leap_second_info(s);
+ VERIFY( lsi.is_leap_second == true );
+ VERIFY( lsi.elapsed == 3s );
+
+ s = std::chrono::utc_seconds(1483228826s); // 1 Jan 2017
+ lsi = get_leap_second_info(s);
+ VERIFY( lsi.is_leap_second == true );
+ VERIFY( lsi.elapsed == 27s );
+
+ // We should not have checked the filesystem for the times above.
+ VERIFY( ! override_used );
+}
+
+void
+test_future_leaps()
+{
+ // Make sure there's no old file from a previous test run.
+ std::ofstream("leapseconds") << "";
+
+ using std::chrono::years;
+ auto s = std::chrono::utc_seconds(1483228826s + years(100)); // 1 Jan 2117
+ auto lsi = get_leap_second_info(s);
+ VERIFY( override_used ); // If this fails then XFAIL for the target.
+ VERIFY( lsi.is_leap_second == false );
+ const auto hardcoded_count = lsi.elapsed;
+ VERIFY( lsi.elapsed == 27s );
+
+ std::ofstream("leapseconds") << R"(
+# No need to repeat the real leap seconds here, they're hardcoded in the lib.
+# These are fake new leap seconds for testing purposes:
+Leap 2099 Dec 31 23:59:60 + S
+Leap 2120 Jun 30 23:59:59 - S
+)";
+
+ override_used = false;
+ std::chrono::reload_tzdb();
+ VERIFY( override_used );
+
+ // Check the same date again using the custom leapseconds file:
+ lsi = get_leap_second_info(s);
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == hardcoded_count + 1s ); // One an extra leap second.
+
+ s = std::chrono::utc_seconds(s + years(10));
+ lsi = get_leap_second_info(s);
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == hardcoded_count ); // And a negative leap second.
+
+ // Overwrite the custom file again:
+ std::ofstream("leapseconds") << "";
+
+ // This should not re-read the custom file, the head of the tzdb_list
+ // should already have been populated by calling get_leap_second_info(s):
+ auto& tzdb = std::chrono::get_tzdb();
+ VERIFY( tzdb.leap_seconds.size() == hardcoded_count.count() + 2 );
+}
+
+int main()
+{
+ test_known_leaps();
+ test_future_leaps();
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc
b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index 8fb38355cadd..4e80c5f184a6 100644
--- a/libstdc++-v3/testsuite/util/testsuite_abi.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc
@@ -217,6 +217,7 @@ check_version(symbol& test, bool added)
known_versions.push_back("GLIBCXX_3.4.33");
known_versions.push_back("GLIBCXX_3.4.34");
known_versions.push_back("GLIBCXX_3.4.35");
+ known_versions.push_back("GLIBCXX_3.4.36");
known_versions.push_back("GLIBCXX_LDBL_3.4.31");
known_versions.push_back("GLIBCXX_IEEE128_3.4.29");
known_versions.push_back("GLIBCXX_IEEE128_3.4.30");
@@ -260,7 +261,7 @@ check_version(symbol& test, bool added)
test.version_status = symbol::incompatible;
// Check that added symbols are added in the latest pre-release version.
- bool latestp = (test.version_name == "GLIBCXX_3.4.35"
+ bool latestp = (test.version_name == "GLIBCXX_3.4.36"
|| test.version_name == "CXXABI_1.3.17"
|| test.version_name == "CXXABI_FLOAT128"
|| test.version_name == "CXXABI_TM_1");
--
2.54.0