From ef29eabf5512c0149bfb8261a9a1bafae5547e00 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tomasz=20Kami=C5=84ski?= Date: Fri, 3 Oct 2025 09:01:21 +0200 Subject: [PATCH] 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 --- 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 df047f1103b..3b1f5862cba 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 constexpr bool enable_nonlocking_formatter_optimization> - = 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 - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = 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 - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template @@ -3130,10 +3136,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template @@ -3172,10 +3180,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template @@ -3214,10 +3224,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template @@ -3256,10 +3268,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template @@ -3297,10 +3311,12 @@ namespace __format }; #if __glibcxx_print >= 202406L - template - constexpr bool - enable_nonlocking_formatter_optimization> - = true; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4400. enable_nonlocking_formatter_optimization for durations with custom rep + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Duration>; #endif template @@ -3364,10 +3380,13 @@ namespace __format }; #if __glibcxx_print >= 202406L - template - 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 + 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 - 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 + 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 ad29f9336e8..281c038559e 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 constexpr bool enable_nonlocking_formatter_optimization> - // TODO this should have remove_cvref_t. - = enable_nonlocking_formatter_optimization<_Fp> - && enable_nonlocking_formatter_optimization<_Sp>; + = enable_nonlocking_formatter_optimization> + && enable_nonlocking_formatter_optimization>; #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 - // TODO this should have remove_cvref_t. constexpr bool enable_nonlocking_formatter_optimization> - = (enable_nonlocking_formatter_optimization<_Tps> && ...); + = (enable_nonlocking_formatter_optimization> && ...); #endif // [format.range.formatter], class template range_formatter diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue index ade09f42ea8..bf2b344c81c 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 constexpr bool - // TODO should be false - enable_nonlocking_formatter_optimization> = true; + enable_nonlocking_formatter_optimization> = 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 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 88bc0d2cb6b..507b9746c8a 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 constexpr bool - // TODO should be false - enable_nonlocking_formatter_optimization> = true; + enable_nonlocking_formatter_optimization> = 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 d9fc01ab893..649eea47f16 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>, CharT>); - // TODO should be false - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor>); - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor>); - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor>>); - static_assert(std::enable_nonlocking_formatter_optimization< + static_assert(!std::enable_nonlocking_formatter_optimization< Adaptor>>); } diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc index 001235ba643..eace82730f0 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>); - // TODO missing remove_cv_ref - static_assert(!std::enable_nonlocking_formatter_optimization< + static_assert(std::enable_nonlocking_formatter_optimization< Tuple>); - static_assert(!std::enable_nonlocking_formatter_optimization< + static_assert(std::enable_nonlocking_formatter_optimization< Tuple>); 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 c7aac75cb83..f1b57b5a348 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 -using local_time_fmt +using local_time_fmt = decltype(std::chrono::local_time_format(std::chrono::local_time{})); - + 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>; 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>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::sys_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::utc_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::gps_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::tai_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::file_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< local_time_fmt>); template<> @@ -92,21 +92,21 @@ inline constexpr bool using NonBufferedRep = std::chrono::duration>; -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>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::sys_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::utc_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::gps_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::tai_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::file_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< local_time_fmt>); using NonBufferedDuration = std::chrono::duration>; @@ -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>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time>); -static_assert(std::enable_nonlocking_formatter_optimization< +static_assert(!std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time>); static_assert(std::enable_nonlocking_formatter_optimization< std::chrono::zoned_time>); @@ -150,7 +150,7 @@ struct std::chrono::zoned_traits { 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>); -- 2.47.3