On Wed, 6 May 2026 at 17:05, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Wed, May 6, 2026 at 5:14 PM Jonathan Wakely <[email protected]> wrote:
>>
>> On Wed, 6 May 2026 at 15:47, Tomasz Kaminski <[email protected]> wrote:
>> >
>> >
>> >
>> > On Wed, May 6, 2026 at 4:18 PM 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. If the OS-provided leapseconds file has a later expiry
>> >> date (or contains new leap seconds added after the one in 2017) then the
>> >> new __detail::__leap_seconds_expiry() function will return that new
>> >> dynamically-obtained expiry date. The __detail::__get_leap_second_info
>> >> function in the header can check that new expiry date instead of relying
>> >> only on the hardcoded one.
>> >>
>> >> This change means that in the worst case we now make two calls into the
>> >> library (one to get the dynamic expiry date and then possibly another
>> >> one to get the actual list of new leap seconds). Previously we just make
>> >> one, to get the list. The change seems worthwhile, because it means that
>> >> in more cases we don't need to increment+decrement the reference count
>> >> on a tzdb object and use its leapseconds vector, we can just use the
>> >> hardcoded array.
>> >>
>> >> The new expiry date is stored in a global variable, rather than being
>> >> per-tzdb object, but that seems fine because we only ever expect that
>> >> expiry date to move forwards in time, not to move forwards and backwards
>> >> as new tzdb objects are loaded by chrono::reload_tzdb(). Even if a new
>> >> list of leap seconds is loaded, we still expect an expiry date that was
>> >> loaded previously to be valid.
>> >
>> > I was wondering about it in connection to the test that overrides the zone 
>> > directory,
>> > and may move the date around. But for those already impacted by the fact 
>> > that
>> > any date with an expiry date before one that we hardcode is ignored. 
>> > However,
>> > for that reason, I would ensure we do not move the date backward; 
>> > suggestion below.
>> > (In also could move backward if reading #experies fails).
>> >
>> >>
>> >>
>> >> 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::__leap_seconds_expiry):
>> >>         Declare new function.
>> >>         (__detail::__get_leap_second_info): Use new function.
>> >>         * src/c++20/tzdb.cc (__detail::__leap_seconds_expiry): Define.
>> >>         (tzdb_list::_Node::_S_read_leap_seconds): Read 'expires' line
>> >>         from leapseconds file and optionally update global cache.
>> >>         * testsuite/std/time/tzdb/leap_seconds.cc: Add expires line to
>> >>         replacement leapseconds file.
>> >>         * testsuite/util/testsuite_abi.cc: Update known_versions and
>> >>         latestp.
>> >> ---
>> >>
>> >> 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               |  9 +-
>> >>  libstdc++-v3/src/c++20/tzdb.cc                | 88 ++++++++++++++++---
>> >>  .../testsuite/std/time/tzdb/leap_seconds.cc   |  1 +
>> >>  libstdc++-v3/testsuite/util/testsuite_abi.cc  |  3 +-
>> >>  7 files changed, 96 insertions(+), 16 deletions(-)
>> >>
>> >> 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..35aaf89984d1 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__detail21__leap_seconds_expiryEv;
>> >> +
>> >> +} 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..228293f12bef 100644
>> >> --- a/libstdc++-v3/include/std/chrono
>> >> +++ b/libstdc++-v3/include/std/chrono
>> >> @@ -3217,6 +3217,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> >>
>> >>  namespace __detail
>> >>  {
>> >> +    // The list below is known to be valid until (at least) this date.
>> >> +    // This value is defined in the library (possibly to a newer value 
>> >> than
>> >> +    // the hardcoded value below) and can change at runtime.
>> >> +    sys_seconds __leap_seconds_expiry();
>> >> +
>> >>      inline leap_second_info
>> >>      __get_leap_second_info(sys_seconds __ss, bool __is_utc)
>> >>      {
>> >> @@ -3252,12 +3257,12 @@ namespace __detail
>> >>         1435708800, // 1 Jul 2015
>> >>         1483228800, // 1 Jan 2017
>> >>        };
>> >> +#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI // use chrono::tzdb
>> >>        // 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 U
>> >
>> >
>> >>
>> >> -#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
>> >> -      if (__ss > __expires)
>> >> +      if (__ss > __expires && __ss > __leap_seconds_expiry())
>> >>         {
>> >>           // Use updated leap_seconds from tzdb.
>> >>           size_t __n = std::size(__leaps);
>> >> diff --git a/libstdc++-v3/src/c++20/tzdb.cc 
>> >> b/libstdc++-v3/src/c++20/tzdb.cc
>> >> index b0fbfc46a6d3..ba0020814ba8 100644
>> >> --- a/libstdc++-v3/src/c++20/tzdb.cc
>> >> +++ b/libstdc++-v3/src/c++20/tzdb.cc
>> >> @@ -1251,6 +1251,40 @@ namespace std::chrono
>> >>    }
>> >>  #endif // TZDB_DISABLED
>> >>
>> >> +namespace
>> >> +{
>> >> +#if ATOMIC_LONG_LOCK_FREE == 2
>> >> +  using expiry_type = unsigned long;
>> >> +#else
>> >> +  using expiry_type = unsigned;
>> >> +#endif
>> >> +  // When GCC 16.1 was released with stable C++20 chrono support (in 
>> >> 2026),
>> >> +  // the last leap second in the list was the one in 2017. If another 
>> >> leap
>>
>> >> +  // second is introduced in future, objects compiled by GCC 16.1 will 
>> >> not
>> >> +  // contain that leap second in the hardcoded list in <chrono>.
>> >> +  // This expiry time must be less than that first post-2017 leap second,
>> >> +  // so that old copies of __get_leap_second_info will use 
>> >> tzdb::leap_seconds
>> >> +  // which will contain the post-2017 leap seconds.
>> >> +  // If no new leap second is introduced, then this expiry time can just 
>> >> be
>> >> +  // updated to the 'expires' value read from the leapseconds file.
>> >> +  // tzdata 2026a leapseconds list expires at 2026-12-28 00:00:00 UTC
>> >> +  constinit std::atomic<expiry_type> 
>> >> leap_seconds_expiry{leap27th_expiry};
>> >
>> > Could you extract the __expires  from 
>> > tzdb_list::_Node::_S_read_leap_seconds()
>> > (in this file)  as the global (but TU-local) variables, and use the 
>> > __expires as initializer here,
>> > so we do not need to update two prices. This will not add any symbols to 
>> > the library, as we are in source file.
>> > (This is why I am not suggesting doing that in header, as we will need to 
>> > make the data inline).
>
> OK, as I understand the code, this value can be updated to one second
> prior to the date of the 28th leap second, or current time, if none was 
> inserted.
> However, the commit message does not contain the number of leap seconds know 
> for GCC17,
>
> Maybe change comment to something like this:
> // When GCC 16.1 was released with stable C++20 chrono support (in 2026),
> // the leap second data contained 27 entries, with the last one in 2017.
> constexpr min_leap_second_count = 27; /// review: use that as magic number, 
> so searching for it will find this comment

Ack.

Reply via email to