On Mon, Oct 26, 2026 at 11:25 AM Tomasz Kaminski <[email protected]>
wrote:

>
>
> On Thu, Oct 15, 2026 at 11:37 AM Jonathan Wakely <[email protected]>
> wrote:
>
>> There is very little code that needs to change, just moving some #if
>> checks and moving a couple of declarations outside hosted-only groups.
>> This adds a new __glibcxx_freestanding_chrono feature test macro.
>> If/when WG21 makes <chrono> freestanding we can remove the no_stdname
>> lines in version.def to also defined __cpp_lib_freestanding_chrono.
>>
>> The parts that can't be freestanding are the now() member functions of
>> the clocks, conversions between sys_time and std::time_t, the
>> file_clock, and everything that depends on chrono::tzdb.
>>
>> The conversions to/from std::time_t depend on the type defined in
>> <time.h>, which is not freestanding. It would be possible to do
>> something like this in chrono::system_clock:
>>
>>   #if _GLIBCXX_HOSTED
>>     using _Sys_clock_time_t = std::time_t;
>>   #else
>>     using _Sys_clock_time_t = long long;
>>   #endif
>>
>> and then define the member functions in terms of that type. That is not
>> done in this change but could be considered in future.
>>
>> Accessing leap second info is supported for freestanding, and therefore
>> so are conversions between utc_time and sys_time. The list of leap
>> seconds is fixed to the hardcoded list in the <chrono> header, so
>> reading an up-to-date list from tzdb is not possible in freestanding.
>>
>> The chrono::zoned_traits and chrono::zoned_time class templates are
>> freestanding, but the chrono::zoned_traits<const time_zone*> partial
>> specialization is not. The default template argument for
>> chrono::zoned_time (which is const time_zone* for hosted) is not present
>> for freestanding, neither are the deduction guides for zoned_time. The
>> zoned_time::get_info member returns sys_info which contains std::string,
>> so that can't be freestanding. The rest of zoned_time can be though.
>> This provides enough functionality for custom time zones to be provided
>> in a freestanding program.
>>
>> The last two `#if _GLIBCXX_HOSTED` checks removed from <chrono> by this
>> commit were redundant, because they surround a check for
>> `__cpp_lib_chrono >= 201803L` which is only true for hosted anyway.
>> Removing those checks is not making chrono::tzdb, chrono::time_zone etc.
>> available for freestanding, just removing the redundancy.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * include/bits/chrono.h (floor, ceil, round): Change
>>         preprocessor condition to __glibcxx_freestanding_chrono.
>>         [!_GLIBCXX_HOSTED] (system_clock, steady_clock): Define.
>>         [!_GLIBCXX_HOSTED] (__sys_t): Remove.
>>         [!_GLIBCXX_HOSTED] (sys_time, sys_seconds, sys_days): Remove
>>         freestanding definitions.
>>         * include/bits/version.def (freestanding_chrono): Define
>>         non-standard macro.
>>         * include/bits/version.h: Regenerate.
>>         * include/std/chrono [!_GLIBCXX_HOSTED] (utc_clock, tai_clock)
>>         (gps_clock): Define.
>>         (clock_time_conversion, clock_cast) [!__STDC_HOSTED__]: Define
>>         the same as for hosted.
>>         * testsuite/20_util/system_clock/1.cc [!__STDC_HOSTED__]: Do not
>>         test now, to_time_t and from_time_t for freestanding.
>>         * testsuite/20_util/system_clock/99832.cc: Require hosted
>>         effective target.
>>         * testsuite/20_util/time_point/comparison_operators/three_way.cc
>>         [!__cpp_lib_hosted]: Do not use system_clock::now() for
>>         freestanding.
>>         * testsuite/std/time/clock/file/members.cc: Require hosted
>>         effective target.
>>         * testsuite/std/time/clock/file/overview.cc [!__STDC_HOSTED__]:
>>         Do not test now() for freestanding.
>>         * testsuite/std/time/clock/gps/1.cc: Likewise.
>>         * testsuite/std/time/clock/tai/1.cc: Likewise.
>>         * testsuite/std/time/format/data_not_present_neg.cc: Require
>>         hosted effective target.
>>         * testsuite/std/time/format/pr120114.cc: Likewise.
>>         * testsuite/std/time/format/pr120481.cc: Likewise.
>>         * testsuite/std/time/format/precision.cc: Likewise.
>>         * testsuite/std/time/format/whitespace.cc: Likewise.
>>         * testsuite/std/time/syn_c++20.cc [!__STDC_HOSTED__]: Do not
>>         test some components for freestanding.
>>         * testsuite/std/time/time_zone/requirements.cc: Require hosted
>>         effective target.
>>         * testsuite/std/time/traits/is_clock.cc [!__STDC_HOSTED__]: Do
>>         not test standard clocks for freestanding.
>>         * testsuite/std/time/zoned_time/custom.cc: Refactor to support
>>         freestanding and old ABI.  Do not require tzdb effective target.
>>         * testsuite/std/time/zoned_time/req_neg.cc: Likewise.
>>         * testsuite/util/slow_clock.h [!_GLIBCXX_HOSTED]: Do not define
>>         slow_clock::now() function for freestanding.
>> ---
>>
>> Tested x86_64-linux, using all my usual RUNTESTFLAGS but also tested the
>> <chrono> parts of the testsuite with -ffreestanding.
>>
>> Also tested with the "only-old-abi" config that I was working on
>> recently, so the combination of no-SSO-string and freestanding also
>> works.
>>
>>  libstdc++-v3/include/bits/chrono.h            | 35 +++----
>>  libstdc++-v3/include/bits/version.def         | 25 ++++-
>>  libstdc++-v3/include/bits/version.h           | 17 ++++
>>  libstdc++-v3/include/std/chrono               | 46 ++++-----
>>  .../testsuite/20_util/system_clock/1.cc       | 10 +-
>>  .../testsuite/20_util/system_clock/99832.cc   |  1 +
>>  .../comparison_operators/three_way.cc         |  4 +
>>  .../testsuite/std/time/clock/file/members.cc  |  1 +
>>  .../testsuite/std/time/clock/file/overview.cc |  1 +
>>  .../testsuite/std/time/clock/gps/1.cc         |  2 +
>>  .../testsuite/std/time/clock/tai/1.cc         |  2 +
>>  .../std/time/format/data_not_present_neg.cc   |  1 +
>>  .../testsuite/std/time/format/pr120114.cc     |  1 +
>>  .../testsuite/std/time/format/pr120481.cc     |  1 +
>>  .../testsuite/std/time/format/precision.cc    |  1 +
>>  .../testsuite/std/time/format/whitespace.cc   |  1 +
>>  libstdc++-v3/testsuite/std/time/syn_c++20.cc  | 21 +++-
>>  .../std/time/time_zone/requirements.cc        |  2 +-
>>  .../testsuite/std/time/traits/is_clock.cc     |  2 +
>>  .../testsuite/std/time/zoned_time/custom.cc   | 96 +++++++++++++------
>>  .../testsuite/std/time/zoned_time/req_neg.cc  |  5 +-
>>  libstdc++-v3/testsuite/util/slow_clock.h      | 14 ++-
>>  22 files changed, 200 insertions(+), 89 deletions(-)
>>
>> diff --git a/libstdc++-v3/include/bits/chrono.h
>> b/libstdc++-v3/include/bits/chrono.h
>> index a71d1435f2f6..0a6be709b76d 100644
>> --- a/libstdc++-v3/include/bits/chrono.h
>> +++ b/libstdc++-v3/include/bits/chrono.h
>> @@ -376,9 +376,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        { };
>>  #endif // C++20
>>
>> -    // This should use __glibcxx_chrono >= 201611L but that implies
>> HOSTED
>> -    // and we want these functions to be freestanding.
>> -#if __cplusplus >= 201703L // C++ >= 17
>> +#if __glibcxx_freestanding_chrono >= 201611L // C++ >= 17
>>      /** Convert a `duration` to type `ToDur` and round down.
>>       *
>>       * If the duration cannot be represented exactly in the result type,
>> @@ -1032,9 +1030,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>         return
>> __time_point(duration_cast<_ToDur>(__t.time_since_epoch()));
>>        }
>>
>> -    // This should use __glibcxx_chrono >= 201611L but that implies
>> HOSTED
>> -    // and we want these functions to be freestanding.
>> -#if __cplusplus >= 201703L // C++ >= 17
>> +#if __glibcxx_freestanding_chrono >= 201611L // C++ >= 17
>>      /** Convert a `time_point` to type `ToDur` and round down.
>>       *
>>       * The result is the same time point as measured by the same clock,
>> but
>> @@ -1208,7 +1204,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>      /// @}
>>      /// @} group chrono
>>
>> -#if _GLIBCXX_HOSTED
>>      // Clocks.
>>
>>      // Why nanosecond resolution as the default?
>> @@ -1248,6 +1243,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>>
>>        static constexpr bool is_steady = false;
>>
>> +#if _GLIBCXX_HOSTED
>>        static time_point
>>        now() noexcept;
>>
>> @@ -1268,6 +1264,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>>         return time_point_cast<system_clock::duration>
>>                (__from(chrono::seconds(__t)));
>>        }
>> +#endif
>>      };
>>
>>
>> @@ -1286,8 +1283,10 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>>
>>        static constexpr bool is_steady = true;
>>
>> +#if _GLIBCXX_HOSTED
>>        static time_point
>>        now() noexcept;
>> +#endif
>>      };
>>
>>
>> @@ -1311,29 +1310,23 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
>>      using sys_seconds = sys_time<seconds>;
>>      using sys_days = sys_time<days>;
>>
>> +    template<> struct is_clock<system_clock> : true_type { };
>> +    template<> inline constexpr bool is_clock_v<system_clock> = true;
>> +
>> +    template<> struct is_clock<steady_clock> : true_type { };
>> +    template<> inline constexpr bool is_clock_v<steady_clock> = true;
>> +
>> +#if _GLIBCXX_HOSTED
>>      using file_clock = ::std::filesystem::__file_clock;
>>
>>      template<typename _Duration>
>>        using file_time = time_point<file_clock, _Duration>;
>>
>> -    template<> struct is_clock<system_clock> : true_type { };
>> -    template<> struct is_clock<steady_clock> : true_type { };
>>      template<> struct is_clock<file_clock> : true_type { };
>> -
>> -    template<> inline constexpr bool is_clock_v<system_clock> = true;
>> -    template<> inline constexpr bool is_clock_v<steady_clock> = true;
>>      template<> inline constexpr bool is_clock_v<file_clock> = true;
>> +#endif
>>      /// @}
>>  #endif // C++20
>> -#elif defined __glibcxx_chrono_cxx20 // C++ >= 20
>> -    // Define a fake clock like chrono::local_t so that sys_time etc.
>> -    // can be used for freestanding.
>> -    struct __sys_t;
>> -    template<typename _Duration>
>> -      using sys_time = time_point<__sys_t, _Duration>;
>> -    using sys_seconds = sys_time<seconds>;
>> -    using sys_days = sys_time<days>;
>> -#endif // _GLIBCXX_HOSTED
>>    } // namespace chrono
>>
>>  #ifdef __glibcxx_chrono_udls // C++ >= 14
>> diff --git a/libstdc++-v3/include/bits/version.def
>> b/libstdc++-v3/include/bits/version.def
>> index 914c1d40db7d..340ef4203e11 100644
>> --- a/libstdc++-v3/include/bits/version.def
>> +++ b/libstdc++-v3/include/bits/version.def
>> @@ -627,12 +627,12 @@ ftms = {
>>    values = {
>>      v = 201611;
>>      cxxmin = 17;
>> -    hosted = yes;
>> +    hosted = yes; // system_clock::now() and steady_clock::now() are
>> hosted
>>    };
>>  };
>>
>>  ftms = {
>> -  // Unofficial macro for chrono features supported for old string ABI.
>> +  // Unofficial macro for <chrono> subset supported for old string ABI.
>>    name = chrono_cxx20;
>>    values = {
>>      v = 202306;
>> @@ -646,6 +646,27 @@ ftms = {
>>    };
>>  };
>>
>> +ftms = {
>> +  // Unofficial macro for <chrono> subset supported for freestanding.
>> +  // This excludes Clock::now() functions and everything that depends on
>> tzdb.
>> +  name = freestanding_chrono;
>> +  values = {
>> +    v = 202306;
>> +    cxxmin = 26;
>> +    no_stdname = yes;
>> +  };
>> +  values = {
>> +    v = 201907;
>> +    cxxmin = 20;
>> +    no_stdname = yes;
>> +  };
>> +  values = {
>> +    v = 201611;
>> +    cxxmin = 17;
>> +    no_stdname = yes;
>> +  };
>> +};
>> +
>>  ftms = {
>>    name = execution;
>>    values = {
>> diff --git a/libstdc++-v3/include/bits/version.h
>> b/libstdc++-v3/include/bits/version.h
>> index 2a12a69ed98b..3175bc1b65b4 100644
>> --- a/libstdc++-v3/include/bits/version.h
>> +++ b/libstdc++-v3/include/bits/version.h
>> @@ -713,6 +713,23 @@
>>  #endif /* !defined(__cpp_lib_chrono_cxx20) */
>>  #undef __glibcxx_want_chrono_cxx20
>>
>> +#if !defined(__cpp_lib_freestanding_chrono)
>> +# if (__cplusplus >  202302L)
>> +#  define __glibcxx_freestanding_chrono 202306L
>> +#  if defined(__glibcxx_want_all) ||
>> defined(__glibcxx_want_freestanding_chrono)
>> +#  endif
>> +# elif (__cplusplus >= 202002L)
>> +#  define __glibcxx_freestanding_chrono 201907L
>> +#  if defined(__glibcxx_want_all) ||
>> defined(__glibcxx_want_freestanding_chrono)
>> +#  endif
>> +# elif (__cplusplus >= 201703L)
>> +#  define __glibcxx_freestanding_chrono 201611L
>> +#  if defined(__glibcxx_want_all) ||
>> defined(__glibcxx_want_freestanding_chrono)
>> +#  endif
>> +# endif
>> +#endif /* !defined(__cpp_lib_freestanding_chrono) */
>> +#undef __glibcxx_want_freestanding_chrono
>> +
>>  #if !defined(__cpp_lib_execution)
>>  # if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED
>>  #  define __glibcxx_execution 201902L
>> diff --git a/libstdc++-v3/include/std/chrono
>> b/libstdc++-v3/include/std/chrono
>> index 2c020ff7a3a9..10e2830b66cf 100644
>> --- a/libstdc++-v3/include/std/chrono
>> +++ b/libstdc++-v3/include/std/chrono
>> @@ -54,6 +54,7 @@
>>  # include <bit> // __countr_zero
>>  #endif
>>  #ifdef __glibcxx_chrono_cxx20
>> +# include <string_view>
>>  # include <bits/stl_algo.h>     // upper_bound
>>  # include <bits/range_access.h> // begin/end for arrays
>>  #endif
>> @@ -96,7 +97,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>      using local_seconds = local_time<seconds>;
>>      using local_days = local_time<days>;
>>
>> -#if _GLIBCXX_HOSTED
>>      class utc_clock;
>>      class tai_clock;
>>      class gps_clock;
>> @@ -153,10 +153,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        using time_point                = chrono::time_point<utc_clock>;
>>        static constexpr bool is_steady = false;
>>
>> +#if _GLIBCXX_HOSTED
>>        [[nodiscard]]
>>        static time_point
>>        now()
>>        { return from_sys(system_clock::now()); }
>> +#endif
>>
>>        template<typename _Duration>
>>         [[nodiscard]]
>> @@ -192,9 +194,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        using time_point                = chrono::time_point<tai_clock>;
>>        static constexpr bool is_steady = false;
>>
>> +#if _GLIBCXX_HOSTED
>>        [[nodiscard]]
>>        static time_point
>>        now();  // in src/c++20/clock.cc
>> +#endif
>>
>>        template<typename _Duration>
>>         [[nodiscard]]
>> @@ -230,9 +234,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        using time_point                = chrono::time_point<gps_clock>;
>>        static constexpr bool is_steady = false;
>>
>> +#if _GLIBCXX_HOSTED
>>        [[nodiscard]]
>>        static time_point
>>        now();  // in src/c++20/clock.cc
>> +#endif
>>
>>        template<typename _Duration>
>>         [[nodiscard]]
>> @@ -252,7 +258,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           return gps_time<_CDur>{__t.time_since_epoch()} - 315964809s;
>>         }
>>      };
>> -#endif // _GLIBCXX_HOSTED
>>
>>      template<typename _DestClock, typename _SourceClock>
>>        struct clock_time_conversion
>> @@ -269,7 +274,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           { return __t; }
>>        };
>>
>> -#if _GLIBCXX_HOSTED
>>      template<>
>>        struct clock_time_conversion<system_clock, system_clock>
>>        {
>> @@ -376,7 +380,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>             return _DestClock::from_utc(__t);
>>           }
>>        };
>> -#endif // _GLIBCXX_HOSTED
>>
>>      /// @cond undocumented
>>      namespace __detail
>> @@ -387,7 +390,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>             clock_time_conversion<_DestClock, _SourceClock>{}(__t);
>>           };
>>
>> -#if _GLIBCXX_HOSTED
>>        template<typename _DestClock, typename _SourceClock, typename
>> _Duration>
>>         concept __clock_convs_sys
>>           = requires (const time_point<_SourceClock, _Duration>& __t) {
>> @@ -417,7 +419,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>               clock_time_conversion<system_clock, utc_clock>{}(
>>                 clock_time_conversion<utc_clock, _SourceClock>{}(__t)));
>>           };
>> -#endif // _GLIBCXX_HOSTED
>>      } // namespace __detail
>>      /// @endcond
>>
>> @@ -427,12 +428,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        inline auto
>>        clock_cast(const time_point<_SourceClock, _Duration>& __t)
>>        requires __detail::__clock_convs<_DestClock, _SourceClock,
>> _Duration>
>> -#if _GLIBCXX_HOSTED
>>         || __detail::__clock_convs_sys<_DestClock, _SourceClock,
>> _Duration>
>>         || __detail::__clock_convs_utc<_DestClock, _SourceClock,
>> _Duration>
>>         || __detail::__clock_convs_sys_utc<_DestClock, _SourceClock,
>> _Duration>
>>         || __detail::__clock_convs_utc_sys<_DestClock, _SourceClock,
>> _Duration>
>> -#endif // _GLIBCXX_HOSTED
>>        {
>>         constexpr bool __direct
>>          = __detail::__clock_convs<_DestClock, _SourceClock, _Duration>;
>> @@ -440,7 +439,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>          {
>>            return clock_time_conversion<_DestClock, _SourceClock>{}(__t);
>>          }
>> -#if _GLIBCXX_HOSTED
>>         else
>>          {
>>            constexpr bool __convert_via_sys_clock
>> @@ -491,7 +489,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>                  }
>>              }
>>          }
>> -#endif // _GLIBCXX_HOSTED
>>        }
>>
>>      // CALENDRICAL TYPES
>> @@ -2528,10 +2525,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>         }
>>      }
>>
>> -#if _GLIBCXX_HOSTED
>> -#if __cpp_lib_chrono >= 201803L
>>      // C++20 [time.zones] Time zones
>>
>> +    template<class _Tp> struct zoned_traits { };
>> +
>> +    enum class choose { earliest, latest };
>> +
>> +#if __cpp_lib_chrono >= 201803L // C++ >= 20 && HOSTED && USE_CXX11_ABI
>>      struct tzdb;
>>
>>      struct sys_info
>> @@ -2622,8 +2622,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        }
>>      /// @endcond
>>
>> -    enum class choose { earliest, latest };
>> -
>>      class time_zone
>>      {
>>      public:
>> @@ -2947,8 +2945,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        seconds _M_s; // == date().time_since_epoch() * value().count()
>>      };
>>
>> -    template<class _Tp> struct zoned_traits { };
>> -
>>      template<>
>>        struct zoned_traits<const time_zone*>
>>        {
>> @@ -2987,6 +2983,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>      string remote_version();
>>
>>      template<typename _Duration, typename _TimeZonePtr = const
>> time_zone*>
>> +      class zoned_time;
>> +#endif // __cpp_lib_chrono >= 201803L
>> +
>> +    template<typename _Duration, typename _TimeZonePtr>
>>        class zoned_time
>>        {
>>         static_assert(__is_duration_v<_Duration>);
>> @@ -3141,10 +3141,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>         get_sys_time() const
>>         { return _M_tp; }
>>
>> +#if __cpp_lib_chrono >= 201803L // C++ >= 20 && HOSTED && USE_CXX11_ABI
>>         [[nodiscard]]
>>         sys_info
>>         get_info() const
>>         { return _M_zone->get_info(_M_tp); }
>> +#endif
>>
>>         [[nodiscard]] friend bool
>>         operator==(const zoned_time&, const zoned_time&) = default;
>> @@ -3157,6 +3159,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           friend class zoned_time;
>>        };
>>
>> +#if __cpp_lib_chrono >= 201803L // C++ >= 20 && HOSTED && USE_CXX11_ABI
>> +
>>      zoned_time() -> zoned_time<seconds>;
>>
>>      template<typename _Duration>
>> @@ -3193,6 +3197,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        -> zoned_time<common_type_t<_Duration, seconds>,
>>                      __time_zone_representation<_TimeZonePtrOrName>>;
>>
> As for freestanding you need to provide your own time zone pointer, the
> above CTADs
> are very useful, as you could do zoned_time tp(my_zone_pointer, time),
> withotu specifying.
>
> I think for freestanding we should define time_zone_representation as:
>   template<typename _TimeZonePtrOrName>
>   struct __time_zone_representation_struct
>   {
>      static_assert(is_convertible_v<_TimeZonePtrOrName, string_view>,
>                           "time_zone is not supported on freedstanding, a
> custom time zone pointer need to provided");
>      using type = remove_cvref_t<_TimeZonePtrOrName>;
>   };
>
>   template<typename _TimeZonePtrOrName>
>     using __time_zone_representation = typename
> __time_zone_representation_struct<_TimeZonePtrOrName>::type;
>
> We want to static_assert on is_convertible to string_view, so we guarantee
> that what is supported on freestanding,
> is true subset of hosted mode. Otherwise, for malicous time_zone_ptr type
> that is convertible to string_view we may get
> different results.
>
>
>
>>
>> +    using zoned_seconds = zoned_time<seconds>;
>> +
>> +#endif // __cpp_lib_chrono >= 201803L
>> +
>>    template<typename _Dur1, typename _TZPtr1, typename _Dur2, typename
>> _TZPtr2>
>>      [[nodiscard]]
>>      inline bool
>> @@ -3203,9 +3211,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>                && __x.get_sys_time() == __y.get_sys_time();
>>      }
>>
>> -    using zoned_seconds = zoned_time<seconds>;
>> -#endif // __cpp_lib_chrono >= 201803L
>> -
>>  namespace __detail
>>  {
>>      // This function is inline to support fast conversions between
>> utc_time
>> @@ -3318,7 +3323,6 @@ namespace __detail
>>         const auto __li = __detail::__get_leap_second_info(__s, false);
>>         return utc_time<_CDur>{__t.time_since_epoch()} + __li.elapsed;
>>        }
>> -#endif // _GLIBCXX_HOSTED
>>
>>      /// @} group chrono
>>  #endif // C++20
>> @@ -3585,7 +3589,6 @@ namespace __detail
>>        }
>>      };
>>
>> -#if _GLIBCXX_HOSTED
>>  #if __cpp_lib_chrono >= 201803L
>>    // zoned_time
>>    template<typename _Duration, typename _TimeZonePtr>
>> @@ -3644,7 +3647,6 @@ namespace __detail
>>        }
>>      };
>>  #endif // __cpp_lib_chrono >= 201803L
>> -#endif // _GLIBCXX_HOSTED
>>  #endif // __glibcxx_chrono_cxx20 >= 202306
>>
>>  #ifdef __glibcxx_chrono_cxx20
>> diff --git a/libstdc++-v3/testsuite/20_util/system_clock/1.cc
>> b/libstdc++-v3/testsuite/20_util/system_clock/1.cc
>> index b0cb3a1ac59e..7541d501321b 100644
>> --- a/libstdc++-v3/testsuite/20_util/system_clock/1.cc
>> +++ b/libstdc++-v3/testsuite/20_util/system_clock/1.cc
>> @@ -28,12 +28,12 @@ main()
>>  {
>>    using namespace std::chrono;
>>
>> -  system_clock::time_point t1 = system_clock::now();
>> -  bool is_steady = system_clock::is_steady;
>> -  is_steady = is_steady; // suppress unused warning
>> +  [[maybe_unused]] system_clock::time_point t1;
>> +#if __STDC_HOSTED__
>> +  t1 = system_clock::now();
>>    std::time_t t2 = system_clock::to_time_t(t1);
>>    system_clock::time_point t3 = system_clock::from_time_t(t2);
>>    t3 = t3; // suppress unused warning
>> -
>> -  return 0;
>> +#endif
>> +  [[maybe_unused]] bool is_steady = system_clock::is_steady;
>>  }
>> diff --git a/libstdc++-v3/testsuite/20_util/system_clock/99832.cc
>> b/libstdc++-v3/testsuite/20_util/system_clock/99832.cc
>> index 693d4d647d9b..7d32cecdcc11 100644
>> --- a/libstdc++-v3/testsuite/20_util/system_clock/99832.cc
>> +++ b/libstdc++-v3/testsuite/20_util/system_clock/99832.cc
>> @@ -1,5 +1,6 @@
>>  // { dg-options "-O0 -g0" }
>>  // { dg-do compile { target c++20 } }
>> +// { dg-require-effective-target hosted }
>>  // { dg-final { scan-assembler-not "system_clock9to_time_t" } }
>>
>>  // Bug libstdc++/99832
>> diff --git
>> a/libstdc++-v3/testsuite/20_util/time_point/comparison_operators/three_way.cc
>> b/libstdc++-v3/testsuite/20_util/time_point/comparison_operators/three_way.cc
>> index 104c4b3bf118..e5c7d7522a03 100644
>> ---
>> a/libstdc++-v3/testsuite/20_util/time_point/comparison_operators/three_way.cc
>> +++
>> b/libstdc++-v3/testsuite/20_util/time_point/comparison_operators/three_way.cc
>> @@ -27,7 +27,11 @@ test01()
>>  {
>>    using namespace std::chrono;
>>
>> +#if __STDC_HOSTED__
>>    auto ns = system_clock::now();
>> +#else
>> +  auto ns = system_clock::time_point(12345s);
>> +#endif
>>    auto s = time_point_cast<seconds>(ns + seconds(2));
>>
>>    VERIFY( s != ns );
>> diff --git a/libstdc++-v3/testsuite/std/time/clock/file/members.cc
>> b/libstdc++-v3/testsuite/std/time/clock/file/members.cc
>> index a23d6b1f9d20..c37015139196 100644
>> --- a/libstdc++-v3/testsuite/std/time/clock/file/members.cc
>> +++ b/libstdc++-v3/testsuite/std/time/clock/file/members.cc
>> @@ -16,6 +16,7 @@
>>  // <http://www.gnu.org/licenses/>.
>>
>>  // { dg-do run { target c++20 } }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <chrono>
>>  #include <testsuite_hooks.h>
>> diff --git a/libstdc++-v3/testsuite/std/time/clock/file/overview.cc
>> b/libstdc++-v3/testsuite/std/time/clock/file/overview.cc
>> index ac56e3d16aba..2d0482204f72 100644
>> --- a/libstdc++-v3/testsuite/std/time/clock/file/overview.cc
>> +++ b/libstdc++-v3/testsuite/std/time/clock/file/overview.cc
>> @@ -16,6 +16,7 @@
>>  // <http://www.gnu.org/licenses/>.
>>
>>  // { dg-do compile { target c++20 } }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <chrono>
>>
>> diff --git a/libstdc++-v3/testsuite/std/time/clock/gps/1.cc
>> b/libstdc++-v3/testsuite/std/time/clock/gps/1.cc
>> index 8be517b316bb..95bdc504a8fe 100644
>> --- a/libstdc++-v3/testsuite/std/time/clock/gps/1.cc
>> +++ b/libstdc++-v3/testsuite/std/time/clock/gps/1.cc
>> @@ -33,6 +33,7 @@ test02()
>>  void
>>  test03()
>>  {
>> +#if __STDC_HOSTED__
>>    using namespace std::chrono;
>>
>>    gps_time<gps_clock::duration> gps1 = gps_clock::now();
>> @@ -45,6 +46,7 @@ test03()
>>
>>    gps_seconds s = time_point_cast<seconds>(gps1);
>>    VERIFY( gps1 - s < 1s );
>> +#endif
>>  }
>>
>>  int main()
>> diff --git a/libstdc++-v3/testsuite/std/time/clock/tai/1.cc
>> b/libstdc++-v3/testsuite/std/time/clock/tai/1.cc
>> index 63cc9927859e..8925d7624149 100644
>> --- a/libstdc++-v3/testsuite/std/time/clock/tai/1.cc
>> +++ b/libstdc++-v3/testsuite/std/time/clock/tai/1.cc
>> @@ -36,6 +36,7 @@ test02()
>>  void
>>  test03()
>>  {
>> +#if __STDC_HOSTED__
>>    using namespace std::chrono;
>>
>>    tai_time<tai_clock::duration> tai1 = tai_clock::now();
>> @@ -48,6 +49,7 @@ test03()
>>
>>    tai_seconds s = time_point_cast<seconds>(tai1);
>>    VERIFY( tai1 - s < 1s );
>> +#endif
>>  }
>>
>>  int main()
>> diff --git
>> a/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> index 5b769d56af55..7e8c1f581ffd 100644
>> --- a/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> +++ b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> @@ -1,4 +1,5 @@
>>  // { dg-do compile { target c++20 } }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <chrono>
>>  #include <format>
>> diff --git a/libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> index cdde4685eda6..c9ec16904079 100644
>> --- a/libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> +++ b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> @@ -1,6 +1,7 @@
>>  // { dg-do run { target c++23 } }
>>  // { dg-options "-fexec-charset=UTF-8" }
>>  // { dg-timeout-factor 2 }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <algorithm>
>>  #include <chrono>
>> diff --git a/libstdc++-v3/testsuite/std/time/format/pr120481.cc
>> b/libstdc++-v3/testsuite/std/time/format/pr120481.cc
>> index a748acb59a9b..e7bd2108e273 100644
>> --- a/libstdc++-v3/testsuite/std/time/format/pr120481.cc
>> +++ b/libstdc++-v3/testsuite/std/time/format/pr120481.cc
>> @@ -1,6 +1,7 @@
>>  // { dg-do run { target c++23 } }
>>  // { dg-options "-fexec-charset=UTF-8" }
>>  // { dg-timeout-factor 2 }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <algorithm>
>>  #include <chrono>
>> diff --git a/libstdc++-v3/testsuite/std/time/format/precision.cc
>> b/libstdc++-v3/testsuite/std/time/format/precision.cc
>> index aa266156c1ff..5425d671199d 100644
>> --- a/libstdc++-v3/testsuite/std/time/format/precision.cc
>> +++ b/libstdc++-v3/testsuite/std/time/format/precision.cc
>> @@ -1,4 +1,5 @@
>>  // { dg-do run { target c++20 } }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <chrono>
>>  #include <ranges>
>> diff --git a/libstdc++-v3/testsuite/std/time/format/whitespace.cc
>> b/libstdc++-v3/testsuite/std/time/format/whitespace.cc
>> index 9637886aae5b..cd5a2840c31b 100644
>> --- a/libstdc++-v3/testsuite/std/time/format/whitespace.cc
>> +++ b/libstdc++-v3/testsuite/std/time/format/whitespace.cc
>> @@ -1,4 +1,5 @@
>>  // { dg-do run { target c++20 } }
>> +// { dg-require-effective-target hosted }
>>
>>  #include <chrono>
>>  #include <testsuite_hooks.h>
>> diff --git a/libstdc++-v3/testsuite/std/time/syn_c++20.cc
>> b/libstdc++-v3/testsuite/std/time/syn_c++20.cc
>> index 62abbc52ad2f..59bb38a01fb3 100644
>> --- a/libstdc++-v3/testsuite/std/time/syn_c++20.cc
>> +++ b/libstdc++-v3/testsuite/std/time/syn_c++20.cc
>> @@ -27,12 +27,25 @@
>>  # define EXPECTED_VALUE 201611L
>>  #endif
>>
>> +#if __STDC_HOSTED__
>> +
>>  #ifndef __cpp_lib_chrono
>>  # error "Feature test macro for chrono is missing in <chrono>"
>>  #elif __cpp_lib_chrono < EXPECTED_VALUE
>>  # error "Feature test macro for chrono has wrong value in <chrono>"
>>  #endif
>>
>> +#else // __cpp_lib_chrono is not defined for freestanding
>> +
>> +#ifndef __glibcxx_freestanding_chrono
>> +# error "Feature test macro for freestanding chrono is missing in
>> <chrono>"
>> +#elif __glibcxx_freestanding_chrono < EXPECTED_VALUE
>> +# error "Feature test macro for chrono has wrong value in <chrono>"
>> +#endif
>> +
>> +#endif
>> +
>> +
>>  namespace __gnu_test
>>  {
>>    // Check for the new additions to <chrono> in C++20
>> @@ -64,8 +77,10 @@ namespace __gnu_test
>>    using std::chrono::gps_time;
>>    using std::chrono::gps_seconds;
>>
>> +#if __STDC_HOSTED__ // no file_clock in freestanding
>>    using std::chrono::file_clock;
>>    using std::chrono::file_time;
>> +#endif
>>
>>    using std::chrono::local_t;
>>    using std::chrono::local_time;
>> @@ -101,7 +116,7 @@ namespace __gnu_test
>>    using std::chrono::make12;
>>    using std::chrono::make24;
>>
>> -#if __cpp_lib_chrono >= 201803L
>> +#if __cpp_lib_chrono >= 201803L // full C++20 tzdb support
>>    using std::chrono::tzdb;
>>    using std::chrono::tzdb_list;
>>    using std::chrono::get_tzdb;
>> @@ -130,10 +145,12 @@ namespace __gnu_test
>>    using std::chrono::time_zone_link;
>>  #endif
>>
>> +#if __STDC_HOSTED__ // no chrono I/O in freestanding
>>    using std::chrono::local_time_format;
>>
>>    using std::chrono::from_stream;
>>    using std::chrono::parse;
>> +#endif
>>
>>    using std::chrono::last;
>>    using std::chrono::Sunday;
>> @@ -197,6 +214,8 @@ namespace __gnu_test
>>    static_assert( is_time_point<local_seconds> );
>>    static_assert( is_time_point<local_days> );
>>
>> +#if __STDC_HOSTED__ // no file_clock in freestanding
>>    static_assert( std::is_class_v<file_clock> );
>>    static_assert( is_time_point<file_time<std::chrono::milliseconds>> );
>> +#endif
>>  }
>> diff --git a/libstdc++-v3/testsuite/std/time/time_zone/requirements.cc
>> b/libstdc++-v3/testsuite/std/time/time_zone/requirements.cc
>> index 929fea2c0eb1..865a7caf917a 100644
>> --- a/libstdc++-v3/testsuite/std/time/time_zone/requirements.cc
>> +++ b/libstdc++-v3/testsuite/std/time/time_zone/requirements.cc
>> @@ -1,5 +1,5 @@
>>  // { dg-do compile { target c++20 } }
>> -// { dg-require-effective-target cxx11_abi }
>> +// { dg-require-effective-target tzdb }
>>
>>  #include <chrono>
>>
>> diff --git a/libstdc++-v3/testsuite/std/time/traits/is_clock.cc
>> b/libstdc++-v3/testsuite/std/time/traits/is_clock.cc
>> index e52691c6f16d..81b16e9a3961 100644
>> --- a/libstdc++-v3/testsuite/std/time/traits/is_clock.cc
>> +++ b/libstdc++-v3/testsuite/std/time/traits/is_clock.cc
>> @@ -22,6 +22,7 @@
>>
>>  namespace chrono = std::chrono;
>>
>> +#if __cpp_lib_chrono >= 201803L
>>  static_assert( chrono::is_clock<chrono::system_clock>::value );
>>  static_assert( chrono::is_clock_v<chrono::system_clock> );
>>
>> @@ -48,6 +49,7 @@ static_assert(
>> chrono::is_clock_v<Clock<chrono::steady_clock>> );
>>
>>  static_assert(chrono::is_clock<Clock<chrono::file_clock>>::value);
>>  static_assert(chrono::is_clock_v<Clock<chrono::file_clock>>);
>> +#endif
>>
>>  static_assert( chrono::is_clock<__gnu_test::slow_clock>::value );
>>  static_assert( chrono::is_clock_v<__gnu_test::slow_clock> );
>> diff --git a/libstdc++-v3/testsuite/std/time/zoned_time/custom.cc
>> b/libstdc++-v3/testsuite/std/time/zoned_time/custom.cc
>> index 83e1f6dca43d..572bed60d4a9 100644
>> --- a/libstdc++-v3/testsuite/std/time/zoned_time/custom.cc
>> +++ b/libstdc++-v3/testsuite/std/time/zoned_time/custom.cc
>> @@ -1,58 +1,94 @@
>>  // { dg-do run { target c++20 } }
>> -// { dg-require-effective-target tzdb }
>>
> I would prefer to have a separate test that uses a "non-pointer" zone
> pointer, something like
> (and do not modify this one):
> struct ZoneOffset
> {
>    minutes offset;
>
>    ZoneOffset operator->() const noexcept
>    { return *this; }
>
>     template<typename Dur>
>       std::chrono::sys_time<Dur> to_sys(const
> std::chrono::local_time<Dur>& tp) const noexcept
>       {
>          return tp - offset;
>       }
>
>     template<typename Dur>
>       std::chrono::local_time<Dur> to_local(const
> std::chrono::sys_time<Dur>& tp) const noexcept
>       {
>          return tp + offset;
>       }
> };
>
> The zoned_traits remains empty (the default constructor and cosntructor
> from string_view are constrained),
> znd then this can be used (assuming CTAD changes):
>
> zoned_time tz{ZoneOffset(10min), ...};
>
We then could link to this test in the documentation, showing how the
zoned_time can be used effectively on such
target, embeding information inside the "pointer", instead of requiring
separate set of variables.

>
>
>>
>>  #include <chrono>
>>  #include <set>
>>  #include <stdexcept>
>>  #include <testsuite_hooks.h>
>>
>> +// Get the name of the current zone.
>> +std::string_view
>> +current_zone_name()
>> +{
>> +#if __cpp_lib_chrono >= 201803L // Full tzdb support
>> +  return std::chrono::current_zone()->name();
>> +#else // freestanding or old ABI
>> +  return "Freestanding/Zone";
>> +#endif
>> +}
>> +
>> +// Get the canonical name of a zone or link.
>> +std::string_view
>> +resolved_zone_name(std::string_view name)
>> +{
>> +#if __cpp_lib_chrono >= 201803L // Full tzdb support
>> +  return std::chrono::locate_zone(name)->name();
>> +#else // freestanding or old ABI
>> +  return name;
>> +#endif
>> +}
>> +
>>  struct local_tz
>>  {
>> -  local_tz() : name(std::chrono::current_zone()->name()) { }
>> +  local_tz() : name(current_zone_name()) { }
>>
>>    explicit local_tz(std::string_view name) : name(name) { }
>>
>>    template<typename Dur>
>> -    std::chrono::sys_time<Dur> to_sys(const
>> std::chrono::local_time<Dur>& d)
>> -    { return std::chrono::locate_zone(name)->to_sys(d); }
>> +    std::chrono::sys_time<Dur> to_sys(const
>> std::chrono::local_time<Dur>& tp)
>> +    {
>> +#if __cpp_lib_chrono >= 201803L // Full tzdb support
>> +      return std::chrono::locate_zone(name)->to_sys(tp);
>> +#else
>> +      return { tp.time_since_epoch() };
>> +#endif
>> +    }
>>
>>    template<typename Dur>
>> -    std::chrono::sys_time<Dur> to_local(const
>> std::chrono::sys_time<Dur>& d)
>> -    { return std::chrono::locate_zone(name)->to_sys(d); }
>> +    std::chrono::local_time<Dur> to_local(const
>> std::chrono::sys_time<Dur>& tp)
>> +    {
>> +#if __cpp_lib_chrono >= 201803L // Full tzdb support
>> +      return std::chrono::locate_zone(name)->to_local(tp);
>> +#else
>> +      return { tp.time_since_epoch() };
>> +#endif
>> +    }
>>
>> +#if __cpp_lib_chrono >= 201803L // Full tzdb support
>>    template<typename Dur>
>> -    std::chrono::sys_info get_info(const std::chrono::sys_time<Dur>& d)
>> -    { return std::chrono::locate_zone(name)->get_info(d); }
>> +    std::chrono::sys_info get_info(const std::chrono::sys_time<Dur>& tp)
>> +    { return std::chrono::locate_zone(name)->get_info(tp); }
>> +#endif
>>
>> -  struct indirect_cmp
>> -  {
>> -    bool operator()(const local_tz* lhs, const local_tz* rhs) const
>> -    { return lhs->name < rhs->name; }
>> -  };
>> -
>> -  bool eq(const std::chrono::time_zone* tz) const noexcept
>> -  { return name == tz->name(); }
>> +  // Not part of the required API, used for testing below.
>> +  bool eq(std::string_view s) const { return s == name; }
>>
>>  private:
>>    std::string_view name;
>> +
>> +  friend struct std::chrono::zoned_traits<const local_tz*>;
>>  };
>>
>>  template<> struct std::chrono::zoned_traits<const local_tz*>
>>  {
>> -  static const local_tz* default_zone()
>> -  {
>> -    return locate_zone(std::chrono::current_zone()->name());
>> -  }
>> +  static const local_tz*
>> +  default_zone() { return locate_zone(current_zone_name()); }
>>
>> -  static const local_tz* locate_zone(std::string_view name)
>> +  static const local_tz*
>> +  locate_zone(std::string_view name)
>>    {
>> -    static std::set<const local_tz*, local_tz::indirect_cmp> zones;
>> -    local_tz tz(name);
>> -    if (auto z = zones.find(&tz); z != zones.end())
>> -      return *z;
>> -    if (std::chrono::locate_zone(name))
>> -      return *zones.insert(new local_tz(tz)).first;
>> -    throw std::runtime_error("zone not found");
>> +#if __cpp_lib_chrono >= 201803L // Full tzdb support
>> +    if (!std::chrono::locate_zone(name))
>> +      throw std::runtime_error("zone not found");
>> +#endif
>> +
>> +    struct cmp
>> +    {
>> +      bool operator()(const local_tz& lhs, const local_tz& rhs) const
>> +      { return lhs.name < rhs.name; }
>> +    };
>> +    static std::set<local_tz, cmp> zones;
>> +
>> +    return &*zones.emplace(name).first;
>>    }
>>  };
>>
>> @@ -62,10 +98,10 @@ test_custom_tzptr()
>>    using namespace std::chrono;
>>
>>    zoned_time<seconds, const local_tz*> z;
>> -  VERIFY( z.get_time_zone()->eq(std::chrono::current_zone()) );
>> +  VERIFY( z.get_time_zone()->eq(current_zone_name()) );
>>
>>    zoned_time<seconds, const local_tz*>
>> z2(std::string_view("Europe/London"));
>> -  VERIFY(
>> z2.get_time_zone()->eq(std::chrono::locate_zone("Europe/London")) );
>> +  VERIFY( z2.get_time_zone()->eq(resolved_zone_name("Europe/London")) );
>>  }
>>
>>  int main()
>> diff --git a/libstdc++-v3/testsuite/std/time/zoned_time/req_neg.cc
>> b/libstdc++-v3/testsuite/std/time/zoned_time/req_neg.cc
>> index 9950a1f8394d..95d95a59c07f 100644
>> --- a/libstdc++-v3/testsuite/std/time/zoned_time/req_neg.cc
>> +++ b/libstdc++-v3/testsuite/std/time/zoned_time/req_neg.cc
>> @@ -1,8 +1,9 @@
>>  // { dg-do compile { target c++20 } }
>> -// { dg-require-effective-target tzdb }
>>
>>  #include <chrono>
>>
>> -std::chrono::zoned_time<std::chrono::year> z; // { dg-error "here" }
>> +struct TZ; // custom zone so this works even for freestanding and old ABI
>> +
>> +std::chrono::zoned_time<std::chrono::year, const TZ*> z; // { dg-error
>> "here" }
>>  // { dg-error "static assertion failed" "" { target *-*-* } 0 }
>>  // { dg-prune-output "common_type" }
>> diff --git a/libstdc++-v3/testsuite/util/slow_clock.h
>> b/libstdc++-v3/testsuite/util/slow_clock.h
>> index f11a1a6410fc..a3138374fead 100644
>> --- a/libstdc++-v3/testsuite/util/slow_clock.h
>> +++ b/libstdc++-v3/testsuite/util/slow_clock.h
>> @@ -32,10 +32,14 @@ struct slow_clock
>>    using time_point = std::chrono::time_point<slow_clock, duration>;
>>    static constexpr bool is_steady = false;
>>
>> -  static time_point now()
>> -  {
>> -    auto real = std::chrono::system_clock::now();
>> -    return time_point{real.time_since_epoch() / 3};
>> -  }
>> +  static time_point now();
>>  };
>> +
>> +#if _GLIBCXX_HOSTED
>> +inline slow_clock::time_point slow_clock::now()
>> +{
>> +  auto real = std::chrono::system_clock::now();
>> +  return time_point{real.time_since_epoch() / 3};
>> +}
>> +#endif
>>  }
>> --
>> 2.56.0
>>
>>

Reply via email to