On Tue, May 12, 2026 at 2:12 AM Jonathan Wakely <[email protected]> wrote:
> 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]> > Given above, it semi-obvious that it LGTM, very small suggestion for test. > 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") << ""; Add override_used = false; after the above line. > > + > + // 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 ); Then repeat the queries from above showing that we now use tzdb (num_leaps_seconds != 0), and finally VERIFY( !override_used ); > +} > + > +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 > >
