https://gcc.gnu.org/g:ef29eabf5512c0149bfb8261a9a1bafae5547e00
commit r16-4352-gef29eabf5512c0149bfb8261a9a1bafae5547e00 Author: Tomasz KamiĆski <[email protected]> Date: Fri Oct 3 09:01:21 2025 +0200 libstdc++: Adjust enable_nonlocking_formatter_optimization specializations [PR121790] This patch addresses several issues related to the additional specializations for enable_nonlocking_formatter_optimization fomr P3235R3 proposal: * LWG4399 [1]: Apply remove_cvref_t to tuple and pair elements when checking if the direct printing optimization is enabled. * LWG4398 [2]: Disable the direct printing optimization for the standard library container adaptors: queue, priority_queue, and stack. * LWG4400 [3]: Enable the direct printing optimization only for durations that use standard arithmetic types. Conditionally enable it for hh_mm_ss and time_points based on their underlying Duration template argument. [1] https://cplusplus.github.io/LWG/issue4399 [2] https://cplusplus.github.io/LWG/issue4398 [3] https://cplusplus.github.io/LWG/issue4400 PR libstdc++/121790 libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (enable_nonlocking_formatter_optimization): Adjust specializations for duration, hh_mm_ss and time_points. * include/std/format (enable_nonlocking_formatter_optimization): Apply remove_cvref_t on pair and tuple elements. * include/std/queue (enable_nonlocking_formatter_optimization): Change specialization value to false. * include/std/stack (enable_nonlocking_formatter_optimization): Change specialization value to false. * testsuite/std/format/ranges/adaptors.cc: Adjusted tests. * testsuite/std/format/tuple.cc: Adjusted tests. * testsuite/std/time/format/nonlocking.cc: Adjusted tests. Reviewed-by: Jonathan Wakely <[email protected]> Diff: --- libstdc++-v3/include/bits/chrono_io.h | 98 +++++++++++++--------- libstdc++-v3/include/std/format | 12 +-- libstdc++-v3/include/std/queue | 10 ++- libstdc++-v3/include/std/stack | 5 +- .../testsuite/std/format/ranges/adaptors.cc | 9 +- libstdc++-v3/testsuite/std/format/tuple.cc | 5 +- .../testsuite/std/time/format/nonlocking.cc | 40 ++++----- 7 files changed, 102 insertions(+), 77 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index df047f1103bd..3b1f5862cba6 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -561,7 +561,7 @@ namespace __format __formatter_chrono(_ChronoSpec<_CharT> __spec) noexcept : _M_spec(__spec) { } - + constexpr typename basic_format_parse_context<_CharT>::iterator _M_parse(basic_format_parse_context<_CharT>& __pc, _ChronoParts __parts, const _ChronoSpec<_CharT>& __def) @@ -2235,10 +2235,12 @@ namespace __format }; #if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep template<typename _Rep, typename _Period> constexpr bool enable_nonlocking_formatter_optimization<chrono::duration<_Rep, _Period>> - = enable_nonlocking_formatter_optimization<_Rep>; + = is_arithmetic_v<_Rep>; #endif template<__format::__char _CharT> @@ -2988,10 +2990,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::hh_mm_ss<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::hh_mm_ss<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI @@ -3079,10 +3083,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::sys_time<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::sys_time<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template<typename _Duration, __format::__char _CharT> @@ -3130,10 +3136,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::utc_time<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::utc_time<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template<typename _Duration, __format::__char _CharT> @@ -3172,10 +3180,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::tai_time<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::tai_time<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template<typename _Duration, __format::__char _CharT> @@ -3214,10 +3224,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::gps_time<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::gps_time<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template<typename _Duration, __format::__char _CharT> @@ -3256,10 +3268,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::file_time<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::file_time<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template<typename _Duration, __format::__char _CharT> @@ -3297,10 +3311,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization<chrono::local_time<_Duration>> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization<chrono::local_time<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template<typename _Duration, __format::__char _CharT> @@ -3364,10 +3380,13 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization< - chrono::__detail::__local_time_fmt<_Duration>> = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization< + chrono::__detail::__local_time_fmt<_Duration>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI @@ -3391,10 +3410,13 @@ namespace __format }; #if __glibcxx_print >= 202406L - template<typename _Duration> - constexpr bool - enable_nonlocking_formatter_optimization< - chrono::zoned_time<_Duration, const chrono::time_zone*>> = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template<typename _Duration> + constexpr bool + enable_nonlocking_formatter_optimization< + chrono::zoned_time<_Duration, const chrono::time_zone*>> + = enable_nonlocking_formatter_optimization<_Duration>; #endif #endif diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index ad29f9336e8f..281c038559e4 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -5873,11 +5873,12 @@ namespace __format }; #if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4399. enable_nonlocking_formatter_optimization for pair and tuple needs remove_cvref_t template<typename _Fp, typename _Sp> constexpr bool enable_nonlocking_formatter_optimization<pair<_Fp, _Sp>> - // TODO this should have remove_cvref_t. - = enable_nonlocking_formatter_optimization<_Fp> - && enable_nonlocking_formatter_optimization<_Sp>; + = enable_nonlocking_formatter_optimization<remove_cvref_t<_Fp>> + && enable_nonlocking_formatter_optimization<remove_cvref_t<_Sp>>; #endif template<__format::__char _CharT, formattable<_CharT>... _Tps> @@ -5899,10 +5900,11 @@ namespace __format }; #if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4399. enable_nonlocking_formatter_optimization for pair and tuple needs remove_cvref_t template<typename... _Tps> - // TODO this should have remove_cvref_t. constexpr bool enable_nonlocking_formatter_optimization<tuple<_Tps...>> - = (enable_nonlocking_formatter_optimization<_Tps> && ...); + = (enable_nonlocking_formatter_optimization<remove_cvref_t<_Tps>> && ...); #endif // [format.range.formatter], class template range_formatter diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue index ade09f42ea8a..bf2b344c81cc 100644 --- a/libstdc++-v3/include/std/queue +++ b/libstdc++-v3/include/std/queue @@ -113,10 +113,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors template<typename _Tp, typename _Container> constexpr bool - // TODO should be false - enable_nonlocking_formatter_optimization<queue<_Tp, _Container>> = true; + enable_nonlocking_formatter_optimization<queue<_Tp, _Container>> = false; #endif template<__format::__char _CharT, typename _Tp, @@ -154,11 +155,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors template<typename _Tp, typename _Container, typename _Comparator> constexpr bool - // TODO should be false enable_nonlocking_formatter_optimization< - priority_queue<_Tp, _Container, _Comparator>> = true; + priority_queue<_Tp, _Container, _Comparator>> = false; #endif _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/stack b/libstdc++-v3/include/std/stack index 88bc0d2cb6bf..507b9746c8a9 100644 --- a/libstdc++-v3/include/std/stack +++ b/libstdc++-v3/include/std/stack @@ -107,10 +107,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors template<typename _Tp, typename _Container> constexpr bool - // TODO should be false - enable_nonlocking_formatter_optimization<stack<_Tp, _Container>> = true; + enable_nonlocking_formatter_optimization<stack<_Tp, _Container>> = false; #endif _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc index d9fc01ab8930..649eea47f168 100644 --- a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc +++ b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc @@ -122,14 +122,13 @@ test_output() // Formatter check if container is formattable, not container elements. static_assert(!std::formattable<Adaptor<int, NotFormattableCont<int>>, CharT>); - // TODO should be false - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor<int>>); - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor<MutFormat>>); - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor<int, std::deque<int>>>); - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor<int, NotFormattableCont<int>>>); } diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc index 001235ba6430..eace82730f0a 100644 --- a/libstdc++-v3/testsuite/std/format/tuple.cc +++ b/libstdc++-v3/testsuite/std/format/tuple.cc @@ -361,10 +361,9 @@ void test_nonblocking() { static_assert(std::enable_nonlocking_formatter_optimization< Tuple<int, float>>); - // TODO missing remove_cv_ref - static_assert(!std::enable_nonlocking_formatter_optimization< + static_assert(std::enable_nonlocking_formatter_optimization< Tuple<const int, const float>>); - static_assert(!std::enable_nonlocking_formatter_optimization< + static_assert(std::enable_nonlocking_formatter_optimization< Tuple<int&, float&>>); static_assert(!std::enable_nonlocking_formatter_optimization< diff --git a/libstdc++-v3/testsuite/std/time/format/nonlocking.cc b/libstdc++-v3/testsuite/std/time/format/nonlocking.cc index c7aac75cb83e..f1b57b5a3485 100644 --- a/libstdc++-v3/testsuite/std/time/format/nonlocking.cc +++ b/libstdc++-v3/testsuite/std/time/format/nonlocking.cc @@ -43,9 +43,9 @@ static_assert(std::enable_nonlocking_formatter_optimization< #endif template<typename Duration> -using local_time_fmt +using local_time_fmt = decltype(std::chrono::local_time_format(std::chrono::local_time<Duration>{})); - + static_assert(std::enable_nonlocking_formatter_optimization< std::chrono::seconds>); static_assert(std::enable_nonlocking_formatter_optimization< @@ -71,19 +71,19 @@ using BufferedDuration = std::chrono::duration<Rep<void, int>>; static_assert(!std::enable_nonlocking_formatter_optimization< BufferedDuration>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::local_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::sys_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::utc_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::gps_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::tai_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::file_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< local_time_fmt<BufferedDuration>>); template<> @@ -92,21 +92,21 @@ inline constexpr bool using NonBufferedRep = std::chrono::duration<Rep<void, long>>; -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< NonBufferedRep>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::local_time<NonBufferedRep>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::sys_time<NonBufferedRep>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::utc_time<NonBufferedRep>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::gps_time<NonBufferedRep>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::tai_time<NonBufferedRep>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::file_time<NonBufferedRep>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< local_time_fmt<NonBufferedRep>>); using NonBufferedDuration = std::chrono::duration<Rep<void, short>>; @@ -135,9 +135,9 @@ static_assert(std::enable_nonlocking_formatter_optimization< #if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI static_assert(std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time<std::chrono::seconds>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time<BufferedDuration>>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time<NonBufferedRep>>); static_assert(std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time<NonBufferedDuration>>); @@ -150,7 +150,7 @@ struct std::chrono::zoned_traits<MyTimeZone> { static const MyTimeZone* default_zone(); static const MyTimeZone* locate_zone(std::string_view name); -}; +}; static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time<std::chrono::seconds, MyTimeZone>>);
