https://gcc.gnu.org/g:6242d85ae39041ddb569ff4eddea8dfd4c06d500

commit r17-5616-g6242d85ae39041ddb569ff4eddea8dfd4c06d500
Author: Jonathan Wakely <[email protected]>
Date:   Tue Oct 13 14:20:04 2026 +0100

    libstdc++: Enable most of <chrono> for freestanding
    
    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 define __cpp_lib_freestanding_chrono.
    
    The parts that can't be freestanding are the now() member functions of
    the clocks (which are defined as deleted), the file_clock, and
    everything that depends on chrono::tzdb.
    
    The sys_time conversions to/from std::time_t depend on the type defined
    in <time.h>, which is not freestanding. Those are modified to use long
    long instead of std::time_t in freestanding mode.
    
    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, as
    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 and the deduction guides which depend on that default
    template argument are not present. 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 chrono::zoned_time deduction guides give an error if a zone name (as
    a type convertible to std::string_view) is given as an argument. For
    string arguments those deduction guides would deduce the TimeZonePtr
    type as const chrono::time_zone* which is not freestanding. Deduction
    works if the argument is a custom time zone type.
    
    Another thing worth explicitly noting is that std::is_clock_v is false
    for all the standard clocks, as that trait requires a working now()
    member function.
    
    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, zoned_time, hash<zoned_time<>>): Define.
            (clock_time_conversion, clock_cast) [!_GLIBCXX_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/req_neg.cc: Likewise.
            * testsuite/util/slow_clock.h [!_GLIBCXX_HOSTED]: Do not define
            slow_clock::now() function for freestanding.
            * testsuite/std/time/zoned_time/custom_freestanding.cc: New
            test.
    
    Co-authored-by: Tomasz KamiƄski <[email protected]>

Diff:
---
 libstdc++-v3/include/bits/chrono.h                 | 58 ++++++++++--------
 libstdc++-v3/include/bits/version.def              | 25 +++++++-
 libstdc++-v3/include/bits/version.h                | 17 ++++++
 libstdc++-v3/include/std/chrono                    | 69 ++++++++++++++--------
 libstdc++-v3/testsuite/20_util/system_clock/1.cc   | 10 ++--
 .../testsuite/20_util/system_clock/99832.cc        |  1 +
 .../time_point/comparison_operators/three_way.cc   |  4 ++
 .../testsuite/std/time/clock/file/members.cc       |  1 +
 .../testsuite/std/time/clock/file/overview.cc      |  1 +
 libstdc++-v3/testsuite/std/time/clock/gps/1.cc     |  2 +
 libstdc++-v3/testsuite/std/time/clock/tai/1.cc     |  2 +
 .../std/time/format/data_not_present_neg.cc        |  1 +
 libstdc++-v3/testsuite/std/time/format/pr120114.cc |  1 +
 libstdc++-v3/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 ++++++-
 .../testsuite/std/time/time_zone/requirements.cc   |  2 +-
 libstdc++-v3/testsuite/std/time/traits/is_clock.cc |  2 +
 .../std/time/zoned_time/custom_freestanding.cc     | 48 +++++++++++++++
 .../testsuite/std/time/zoned_time/req_neg.cc       |  5 +-
 libstdc++-v3/testsuite/util/slow_clock.h           | 14 +++--
 22 files changed, 224 insertions(+), 63 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono.h 
b/libstdc++-v3/include/bits/chrono.h
index a71d1435f2f6..b636c6cc3008 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;
 
@@ -1264,10 +1260,26 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
       static time_point
       from_time_t(std::time_t __t) noexcept
       {
-       typedef chrono::time_point<system_clock, seconds>       __from;
-       return time_point_cast<system_clock::duration>
-              (__from(chrono::seconds(__t)));
+       using __sys_seconds = chrono::time_point<system_clock, seconds>;
+       return time_point_cast<duration>(__sys_seconds(chrono::seconds(__t)));
+      }
+#else
+      static time_point now() = delete;
+
+      // Map to C API
+      [[__gnu__::__always_inline__]]
+      static long long
+      to_time_t(const time_point& __t) noexcept
+      { return duration_cast<chrono::seconds>(__t.time_since_epoch()).count(); 
}
+
+      [[__gnu__::__always_inline__]]
+      static time_point
+      from_time_t(long long __t) noexcept
+      {
+       using __sys_seconds = chrono::time_point<system_clock, seconds>;
+       return time_point_cast<duration>(__sys_seconds(chrono::seconds(__t)));
       }
+#endif
     };
 
 
@@ -1286,8 +1298,12 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
 
       static constexpr bool is_steady = true;
 
+#if _GLIBCXX_HOSTED
       static time_point
       now() noexcept;
+#else
+      static time_point now() = delete;
+#endif
     };
 
 
@@ -1311,29 +1327,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..6244a31fd5f0 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,14 @@ _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()); }
+#else
+      static time_point now() = delete;
+#endif
 
       template<typename _Duration>
        [[nodiscard]]
@@ -192,9 +196,13 @@ _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
+#else
+      static time_point now() = delete;
+#endif
 
       template<typename _Duration>
        [[nodiscard]]
@@ -230,9 +238,13 @@ _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
+#else
+      static time_point now() = delete;
+#endif
 
       template<typename _Duration>
        [[nodiscard]]
@@ -252,7 +264,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 +280,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          { return __t; }
       };
 
-#if _GLIBCXX_HOSTED
     template<>
       struct clock_time_conversion<system_clock, system_clock>
       {
@@ -376,7 +386,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            return _DestClock::from_utc(__t);
          }
       };
-#endif // _GLIBCXX_HOSTED
 
     /// @cond undocumented
     namespace __detail
@@ -387,7 +396,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 +425,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 +434,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 +445,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         {
           return clock_time_conversion<_DestClock, _SourceClock>{}(__t);
         }
-#if _GLIBCXX_HOSTED
        else
         {
           constexpr bool __convert_via_sys_clock
@@ -491,7 +495,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                 }
             }
         }
-#endif // _GLIBCXX_HOSTED
       }
 
     // CALENDRICAL TYPES
@@ -2528,10 +2531,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 +2628,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
     /// @endcond
 
-    enum class choose { earliest, latest };
-
     class time_zone
     {
     public:
@@ -2947,8 +2951,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 +2989,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 +3147,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,18 +3165,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          friend class zoned_time;
       };
 
+#if __cpp_lib_chrono >= 201803L // C++ >= 20 && HOSTED && USE_CXX11_ABI
+    using zoned_seconds = zoned_time<seconds>;
+
     zoned_time() -> zoned_time<seconds>;
 
     template<typename _Duration>
     zoned_time(sys_time<_Duration>)
       -> zoned_time<common_type_t<_Duration, seconds>>;
+#endif // __cpp_lib_chrono >= 201803L
 
   /// @cond undocumented
+#if __cpp_lib_chrono >= 201803L // C++ >= 20 && HOSTED && USE_CXX11_ABI
   template<typename _TimeZonePtrOrName>
     using __time_zone_representation
       = __conditional_t<is_convertible_v<_TimeZonePtrOrName, string_view>,
                        const time_zone*,
                        remove_cvref_t<_TimeZonePtrOrName>>;
+#else
+  template<typename _TimeZonePtrOrName>
+    struct __time_zone_representation_struct
+    {
+       static_assert(!is_convertible_v<_TimeZonePtrOrName, string_view>,
+                    "std::chrono::time_zone is not defined for freestanding,"
+                    " a custom time zone pointer must be provided");
+       using type = remove_cvref_t<_TimeZonePtrOrName>;
+    };
+
+  template<typename _TimeZonePtrOrName>
+    using __time_zone_representation
+      = typename __time_zone_representation_struct<_TimeZonePtrOrName>::type;
+#endif // __cpp_lib_chrono >= 201803L
   /// @endcond
 
   template<typename _TimeZonePtrOrName>
@@ -3203,9 +3230,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 +3342,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,8 +3608,6 @@ namespace __detail
       }
     };
 
-#if _GLIBCXX_HOSTED
-#if __cpp_lib_chrono >= 201803L
   // zoned_time
   template<typename _Duration, typename _TimeZonePtr>
     requires __is_hash_enabled_for<
@@ -3614,9 +3635,11 @@ namespace __detail
 
        const auto __izone = [&] {
          const _TimeZonePtr __tz = __val.get_time_zone();
+#if __cpp_lib_chrono >= 201803L // C++ >= 20 && HOSTED && USE_CXX11_ABI
          if constexpr (is_same_v<_TimeZonePtr, const chrono::time_zone*>)
            return reinterpret_cast<uintptr_t>(__tz);
          else
+#endif
            return hash<_TimeZonePtr>{}(__tz);
        }();
 
@@ -3631,6 +3654,7 @@ namespace __detail
             __is_fast_hash<hash<_TimeZonePtr>>>
     {};
 
+#if __cpp_lib_chrono >= 201803L
   // leap_second
   template<>
     struct hash<chrono::leap_second>
@@ -3644,7 +3668,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_freestanding.cc 
b/libstdc++-v3/testsuite/std/time/zoned_time/custom_freestanding.cc
new file mode 100644
index 000000000000..a8ac745453ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/zoned_time/custom_freestanding.cc
@@ -0,0 +1,48 @@
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <type_traits>
+#include <testsuite_hooks.h>
+
+struct zone_offset
+{
+  std::chrono::seconds offset;
+
+  template<typename Dur>
+    std::chrono::local_time<std::common_type_t<Dur, std::chrono::seconds>>
+    to_local(const std::chrono::sys_time<Dur>& tp) const noexcept
+    { return std::chrono::local_time<std::common_type_t<Dur, 
std::chrono::seconds>>(tp.time_since_epoch() + offset); }
+
+  template<typename Dur>
+    std::chrono::sys_time<std::common_type_t<Dur, std::chrono::seconds>>
+    to_sys(const std::chrono::local_time<Dur>& tp) const noexcept
+    { return std::chrono::sys_time<std::common_type_t<Dur, 
std::chrono::seconds>>(tp.time_since_epoch() - offset); }
+
+  // Allows zone_offset to be stored directly in zoned_time
+  const zone_offset* operator->() const noexcept
+  { return this; }
+};
+
+void
+test_custom_tzptr()
+{
+  using namespace std::chrono;
+
+  static_assert( !std::is_default_constructible_v<zoned_time<seconds, 
zone_offset>> );
+  static_assert( !std::is_constructible_v<zoned_time<seconds, zone_offset>, 
std::string_view> );
+
+  zoned_time z1(zone_offset{1h}, sys_days(2012y/December/12) + 12h);
+  static_assert( std::is_same_v<decltype(z1), zoned_time<seconds, 
zone_offset>> );
+  VERIFY( z1.get_sys_time() == sys_days(2012y/December/12) + 12h );
+  VERIFY( z1.get_local_time() == local_days(2012y/December/12) + 13h );
+
+  zoned_time z2(zone_offset{1h}, local_days(2012y/December/12) + 12h);
+  static_assert( std::is_same_v<decltype(z2), zoned_time<seconds, 
zone_offset>> );
+  VERIFY( z2.get_sys_time() == sys_days(2012y/December/12) + 11h );
+  VERIFY( z2.get_local_time() == local_days(2012y/December/12) + 12h );
+}
+
+int main()
+{
+  test_custom_tzptr();
+}
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
 }

Reply via email to