+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 359545c4bce..bc9dce5e288 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -51429,7 +51429,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 674f867dcdc..692fd6025e7 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);
-
- 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
+#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.
+
+ // 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);
+ return __after_last;
+ }
- // 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) };
+ seconds::rep __s = __ss.time_since_epoch().count();
+ const seconds::rep* __first = std::begin(__leaps);
+ const seconds::rep* __last = std::end(__leaps);
- auto __pos = std::upper_bound(__first, __last, __s);
- seconds __elapsed{__pos - __first};
- if (__is_utc)
+ // 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])
{
- // 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;
- }
+ if ((__s + 1) >= __pos[-1])
+ return {true, __elapsed};
+ --__elapsed;
}
- return {false, __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 b0fbfc46a6d..0013ad1877c 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
@@ -66,6 +67,7 @@
#endif
#if USE_ATOMIC_SHARED_PTR && ! USE_ATOMIC_LIST_HEAD
+// Cannot use atomic<shared_ptr<T>> without lock-free atomic<T*>.
# error Unsupported combination
#endif
@@ -196,6 +198,13 @@ 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[];
+
+ // This is a member so that it can access fixed_leaps.
+ struct NumLeapSeconds;
+ static NumLeapSeconds num_leap_seconds;
};
// Implementation of the private constructor used for the singleton object.
@@ -1251,56 +1260,240 @@ 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.
+struct tzdb_list::_Node::NumLeapSeconds
+{
+ // Called by __recent_leap_second_info to read num_leap_seconds.
+ unsigned
+ get()
+ {
+#if ATOMIC_INT_LOCK_FREE == 2
+ atomic_ref<unsigned> ref(count);
+ auto num = ref.load(memory_order::relaxed);
+
+ if (num == std::size(_Node::fixed_leaps))
+ // A leapseconds file has been read and has no new leap seconds.
+ return num;
+
+ if (num == 0)
+ // No leapseconds file has been read yet.
+ return 0;
+
+ // The tzdb_list has been initialized and contains a tzdb object with
+ // new leap seconds, which the caller is going to use.
+ // The relaxed load above does not synchronize with anything, so to
+ // ensure that the get_tzdb_list() in the caller will see a tzdb object
+ // set by _S_replace_head, we load num_leap_seconds again with acquire
+ // ordering:
+ return ref.load(memory_order::acquire);
+#else
+ lock_guard<mutex> l(list_mutex()); // This ensures acquire ordering.
+ return count;
+#endif
+ }
+
+ // Called by __recent_leap_second_info to set num_leap_seconds when
+ // we have determined there are no new leap seconds in a leapseconds file.
+ void
+ set_to_fixed_size()
+ {
+#if ATOMIC_INT_LOCK_FREE == 2
+ atomic_ref<unsigned> ref(count);
+ unsigned expected = 0;
+ ref.compare_exchange_strong(expected, std::size(_Node::fixed_leaps),
+ memory_order::relaxed);
+#else
+ lock_guard<mutex> l(list_mutex());
+ if (count == 0)
+ count = std::size(_Node::fixed_leaps);
+#endif
+ }
+
+ // Called by _Node::_S_replace_head
+ // The two versions are named differently so that caller has to be explicit
+ // about which version it calls, based on whether the mutex is held.
+ void
+ set(unsigned val)
+ {
+#if ATOMIC_INT_LOCK_FREE == 2
+ atomic_ref<unsigned> ref(count);
+ // The release op here synchronizes with the acquire op in get().
+ ref.store(val, memory_order::release);
+#else
+ lock_guard<mutex> l(list_mutex());
+ count = val;
+#endif
+ }
+
+ void
+ set_locked(unsigned val, const lock_guard<mutex>&)
+ {
+#if ATOMIC_INT_LOCK_FREE == 2
+ // Even though the caller locked the mutex, we still need to use an
+ // atomic store in this case, because there could be concurrent loads.
+ set(val);
+#else
+ // The only caller of this function locks list_mutex() so we would
+ // deadlock if we locked it again here.
+ count = val;
+#endif
+ }
+
+private:
+ unsigned count = 0;
+};
+
+constinit tzdb_list::_Node::NumLeapSeconds tzdb_list::_Node::num_leap_seconds;
+
+ 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 = _Node::num_leap_seconds.get();
+ 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 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.
+ _Node::num_leap_seconds.set_to_fixed_size();
+ 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 +1502,7 @@ namespace std::chrono
if (!s.starts_with("Leap"))
continue;
+
istringstream li(std::move(s));
li.exceptions(ios::failbit);
li.ignore(4);
@@ -1339,12 +1533,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
@@ -1402,8 +1598,13 @@ namespace std::chrono
new_head_ptr->next = curr;
}
// XXX small window here where _S_head_cache still points to previous tzdb.
+ _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.
+ num_leap_seconds.set(new_head_ptr->db.leap_seconds.size());
#else
- lock_guard<mutex> l(list_mutex());
+ lock_guard<mutex> lock(list_mutex());
if (const _Node* h = _S_head_owner.get())
{
if (h->db.version == new_head_ptr->db.version)
@@ -1411,8 +1612,11 @@ namespace std::chrono
new_head_ptr->next = _S_head_owner;
}
_S_head_owner = std::move(new_head);
-#endif
_S_cache_list_head(new_head_ptr);
+
+ num_leap_seconds.set_locked(new_head_ptr->db.leap_seconds.size(), lock);
+#endif
+
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 00000000000..090a28291c8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/clock/utc/leap_second_info-2.cc
@@ -0,0 +1,108 @@
+// { 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()
+{
+ // XXX adjust this if real leap seconds are added to the hardcoded lists:
+ const auto hardcoded_count = 27s;
+
+ // 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 );
+ VERIFY( lsi.elapsed == hardcoded_count );
+ lsi = get_leap_second_info(s + years(10));
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == hardcoded_count );
+
+ 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
+Leap 2120 Dec 30 23:59:59 - S
+)";
+
+ override_used = false;
+ std::chrono::reload_tzdb();
+ VERIFY( override_used );
+
+ // Check the same dates 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 positive leap second.
+ lsi = get_leap_second_info(s + years(10));
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == hardcoded_count - 1s ); // Two negative leap seconds.
+
+ // Overwrite the custom file again:
+ override_used = false;
+ 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();
+ // The file was not read again:
+ VERIFY( ! override_used );
+ // The list in the tzdb contains the three fake leap seconds:
+ VERIFY( tzdb.leap_seconds.size() == hardcoded_count.count() + 3 );
+ // And repeating the queries above gives the same results:
+ lsi = get_leap_second_info(s);
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == hardcoded_count + 1s ); // One positive leap second.
+ lsi = get_leap_second_info(s + years(10));
+ VERIFY( lsi.is_leap_second == false );
+ VERIFY( lsi.elapsed == hardcoded_count - 1s ); // Two negative leap seconds.
+}
+
+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 8fb38355cad..4e80c5f184a 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.55.0