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