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), ...};


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