From 08782a5d92bacc3af947caf79d19bf25eae02e7b Mon Sep 17 00:00:00 2001 From: Jonathan Wakely <jwakely@redhat.com> Date: Tue, 16 Jul 2024 10:14:45 +0100 Subject: [PATCH] libstdc++: Define C++26 member visit for std::basic_format_arg [PR110356] 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 6dca2d9467aa..0f0cc7cd6599 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 806f1e9549be..ec330911d665 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 e8ca0faf5dcd..148ee87e087c 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 6a88705ec7b9..715fdf934924 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) @@ -4297,6 +4312,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 16ca71caecbe..2cea0a1b63f4 100644 --- a/libstdc++-v3/testsuite/std/format/arguments/args.cc +++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc @@ -1,5 +1,7 @@ // { dg-do run { target c++20 } } +// { dg-warning "deprecated" "std::visit_format_arg" { target c++26 } 0 } + #include <format> #include <testsuite_hooks.h> @@ -55,6 +57,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)); @@ -106,8 +111,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 3c441d711b3e..0549d171e5a2 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 b0cef2da41bc..88ffd77debe0 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)); -- GitLab