Tested x86_64-linux.

-- >8 --

Implement the std::format changes from P2637R3. This adds visit member
functions to std::basic_format_arg and deprecates the non-member
function std::visit_format_arg.

libstdc++-v3/ChangeLog:

        PR libstdc++/110356
        * include/bits/c++config (_GLIBCXX26_DEPRECATED): Define.
        (_GLIBCXX26_DEPRECATED_SUGGEST): Define.
        * include/bits/version.def (format): Update for C++26.
        * include/bits/version.h: Regenerate.
        * include/std/format (basic_format_arg::visit): New member
        functions.
        (visit_format_arg): Add deprecated attribute.
        * testsuite/std/format/arguments/args.cc: Expect deprecated
        warnings. Check member visit.
        * testsuite/std/format/functions/format.cc: Update expected
        value for __cpp_lib_format macro.
        * testsuite/std/format/parse_ctx.cc: Add dg-warning for
        deprecation.
---
 libstdc++-v3/include/bits/c++config           | 10 +++++
 libstdc++-v3/include/bits/version.def         |  2 +-
 libstdc++-v3/include/bits/version.h           |  4 +-
 libstdc++-v3/include/std/format               | 16 +++++++
 .../testsuite/std/format/arguments/args.cc    | 43 +++++++++++++++++++
 .../testsuite/std/format/functions/format.cc  |  4 +-
 .../testsuite/std/format/parse_ctx.cc         |  2 +-
 7 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/bits/c++config 
b/libstdc++-v3/include/bits/c++config
index 6dca2d9467a..0f0cc7cd659 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -90,6 +90,8 @@
 //   _GLIBCXX20_DEPRECATED_SUGGEST( string-literal )
 //   _GLIBCXX23_DEPRECATED
 //   _GLIBCXX23_DEPRECATED_SUGGEST( string-literal )
+//   _GLIBCXX26_DEPRECATED
+//   _GLIBCXX26_DEPRECATED_SUGGEST( string-literal )
 #ifndef _GLIBCXX_USE_DEPRECATED
 # define _GLIBCXX_USE_DEPRECATED 1
 #endif
@@ -143,6 +145,14 @@
 # define _GLIBCXX23_DEPRECATED_SUGGEST(ALT)
 #endif
 
+#if defined(__DEPRECATED) && (__cplusplus >= 202400L)
+# define _GLIBCXX26_DEPRECATED [[__deprecated__]]
+# define _GLIBCXX26_DEPRECATED_SUGGEST(ALT) _GLIBCXX_DEPRECATED_SUGGEST(ALT)
+#else
+# define _GLIBCXX26_DEPRECATED
+# define _GLIBCXX26_DEPRECATED_SUGGEST(ALT)
+#endif
+
 // Macros for ABI tag attributes.
 #ifndef _GLIBCXX_ABI_TAG_CXX11
 # define _GLIBCXX_ABI_TAG_CXX11 __attribute ((__abi_tag__ ("cxx11")))
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 806f1e9549b..ec330911d66 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1171,7 +1171,7 @@ ftms = {
   // 202306 P2637R3 Member visit
   // 202311 P2918R2 Runtime format strings II
   values = {
-    v = 202305;
+    v = 202306;
     cxxmin = 26;
     hosted = yes;
   };
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index e8ca0faf5dc..148ee87e087 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1310,9 +1310,9 @@
 
 #if !defined(__cpp_lib_format)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
-#  define __glibcxx_format 202305L
+#  define __glibcxx_format 202306L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_format)
-#   define __cpp_lib_format 202305L
+#   define __cpp_lib_format 202306L
 #  endif
 # elif (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
 #  define __glibcxx_format 202304L
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 0e61bc5e6bc..f1a1f736a80 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -3346,6 +3346,18 @@ namespace __format
       explicit operator bool() const noexcept
       { return _M_type != __format::_Arg_none; }
 
+#if __cpp_lib_format >= 202306L // >= C++26
+      template<typename _Visitor>
+       decltype(auto)
+       visit(this basic_format_arg __arg, _Visitor&& __vis)
+       { return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type); }
+
+      template<typename _Res, typename _Visitor>
+       _Res
+       visit(this basic_format_arg __arg, _Visitor&& __vis)
+       { return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type); }
+#endif
+
     private:
       template<typename _Ctx>
        friend class basic_format_args;
@@ -3631,6 +3643,7 @@ namespace __format
     };
 
   template<typename _Visitor, typename _Context>
+    _GLIBCXX26_DEPRECATED_SUGGEST("std::basic_format_arg::visit")
     inline decltype(auto)
     visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
     {
@@ -3666,6 +3679,8 @@ namespace __format
       }
   };
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
   template<typename _Context>
     inline size_t
     __int_from_arg(const basic_format_arg<_Context>& __arg)
@@ -4299,6 +4314,7 @@ namespace __format
       else
        return std::move(__sink)._M_finish().out;
     }
+#pragma GCC diagnostic pop
 
 } // namespace __format
 /// @endcond
diff --git a/libstdc++-v3/testsuite/std/format/arguments/args.cc 
b/libstdc++-v3/testsuite/std/format/arguments/args.cc
index eba129ff894..4e0eb69262b 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/args.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc
@@ -3,6 +3,8 @@
 #include <format>
 #include <testsuite_hooks.h>
 
+// { dg-warning "deprecated" "" { target c++26 } 0 }
+
 template<typename Ctx, typename T>
 bool equals(std::basic_format_arg<Ctx> fmt_arg, T expected) {
   return std::visit_format_arg([=](auto arg_val) {
@@ -51,6 +53,9 @@ test_args()
   char c = '2';
   double d = 3.4;
 
+  // We need an lvalue of type format-arg-store<Context, Args...> for the
+  // lvalue args to point to, otherwise it will have a dangling pointer.
+  // This is not how you're supposed to use format args, just for testing.
   auto store = std::make_format_args(b, i, c, d);
   std::format_args args = store;
   VERIFY(equals(args.get(0), false));
@@ -102,8 +107,46 @@ test_args()
   VERIFY(std::visit_format_arg(is_handle, args.get(1)));
 }
 
+void
+test_member_visit()
+{
+#if __cpp_lib_format >= 202306L // C++26 adds std::basic_format_arg::visit
+  int one = 1;
+  float two = 2.0;
+  std::string_view three = "three";
+  auto store = std::make_format_args(one, two, three); // See comment above.
+  std::format_args args = store;
+  auto a1 = args.get(0).visit([=](auto a) {
+    if constexpr (std::is_same_v<decltype(a), int>)
+      return a == one;
+    return false;
+  });
+  VERIFY( a1 );
+  auto a2 = args.get(1).visit([=](auto a) {
+    if constexpr (std::is_same_v<decltype(a), float>)
+      return a == two;
+    return false;
+  });
+  VERIFY( a2 );
+  auto a3 = args.get(2).visit([=](auto a) {
+    if constexpr (std::is_same_v<decltype(a), std::string_view>)
+      return a == three;
+    return false;
+  });
+  VERIFY( a3 );
+
+  auto a4 = args.get(0).visit<std::string_view>([](auto) { return "str"; });
+  static_assert( std::is_same_v<decltype(a4), std::string_view> );
+  VERIFY( a4 == "str" );
+  args.get(0).visit<void>([](auto){});
+  using V = decltype(args.get(0).visit<void>([](auto){}));
+  static_assert( std::is_same_v<V, void> );
+#endif
+}
+
 int main()
 {
   test_empty();
   test_args();
+  test_member_visit();
 }
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc 
b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 3c441d711b3..0549d171e5a 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -8,7 +8,7 @@
 # error "Feature test macro for std::format is missing in <format>"
 #elif __cpp_lib_format < 202110L
 # error "Feature test macro for std::format has wrong value in <format>"
-#elif __cplusplus > 202302L && __cpp_lib_format < 202305L
+#elif __cplusplus > 202302L && __cpp_lib_format < 202306L
 # error "Feature test macro for std::format has wrong value in <format>"
 #endif
 
@@ -24,7 +24,7 @@
 # error "Feature test macro for std::format is missing in <version>"
 #elif __cpp_lib_format < 202110L
 # error "Feature test macro for std::format has wrong value in <version>"
-#elif __cplusplus > 202302L && __cpp_lib_format < 202305L
+#elif __cplusplus > 202302L && __cpp_lib_format < 202306L
 # error "Feature test macro for std::format has wrong value in <version>"
 #endif
 
diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc 
b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
index b0cef2da41b..88ffd77debe 100644
--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
@@ -473,7 +473,7 @@ struct std::formatter<X, char>
   std::format_context::iterator
   format(X, std::format_context& c) const
   {
-    std::visit_format_arg([this]<typename T>(T) {
+    std::visit_format_arg([this]<typename T>(T) { // { dg-warning "deprecated" 
"" { target c++26 } }
       if (is_integral_v<T> != this->integer)
        throw std::format_error("invalid argument type");
     }, c.arg(1));
-- 
2.45.2

Reply via email to