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
>
>

Reply via email to