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

Reply via email to