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 }
