[libcxx-commits] [libcxx] 606e280 - [libc++][format] Use forwarding references.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 10 08:19:36 PDT 2022


Author: Mark de Wever
Date: 2022-07-10T17:19:28+02:00
New Revision: 606e280811f2e17dd3561968139873857dc0a6f8

URL: https://github.com/llvm/llvm-project/commit/606e280811f2e17dd3561968139873857dc0a6f8
DIFF: https://github.com/llvm/llvm-project/commit/606e280811f2e17dd3561968139873857dc0a6f8.diff

LOG: [libc++][format] Use forwarding references.

This implements a not accepted LWG issue. Not doing so would require
integral types to use the handle class instead of being directly stored
in the basic_format_arg.

The previous code used `std::forward` in places where it wasn't required
by the Standard. These are now removed.

Implements:
- P2418R2 Add support for std::generator-like types to std::format
- LWG 3631 basic_format_arg(T&&) should use remove_cvref_t<T> throughout

Reviewed By: ldionne, #libc

Differential Revision: https://reviews.llvm.org/D127570

Added: 
    libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/docs/Status/Cxx2bIssues.csv
    libcxx/include/__format/format_arg.h
    libcxx/include/__format/format_arg_store.h
    libcxx/include/format
    libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
    libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format.verify.cpp
    libcxx/test/std/utilities/format/format.functions/format_tests.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index c6eb835f97393..b564017bf6728 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -47,6 +47,7 @@ Implemented Papers
 - N4190 (Removing auto_ptr, random_shuffle(), And Old <functional> Stuff)
 - P0154R1 (Hardware inference size)
 - P0618R0 (Deprecating <codecvt>)
+- P2418R2 (Add support for ``std::generator``-like types to ``std::format``)
 
 - Marked the following papers as "Complete" (note that some of those might have
   been implemented in a previous release but not marked as such):
@@ -84,6 +85,9 @@ New Features
   of throwing an exception at run-time.  (This does not affect the ``v``
   functions.)
 
+- All format functions in ``<format>`` allow the usage of non-copyable types as
+  argument for the formatting functions. This change causes bit fields to become
+  invalid arguments for the formatting functions.
 
 API Changes
 -----------

diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index d00be2aefb944..e44a75e3ffc8a 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -203,5 +203,5 @@
 "","","","","",""
 "`P2372R3 <https://wg21.link/P2372R3>`__","LWG","Fixing locale handling in chrono formatters","October 2021","",""
 "`P2415R2 <https://wg21.link/P2415R2>`__","LWG","What is a ``view``","October 2021","|Complete|","14.0"
-"`P2418R2 <https://wg21.link/P2418R2>`__","LWG","Add support for ``std::generator``-like types to ``std::format``","October 2021","|Partial|",""
+"`P2418R2 <https://wg21.link/P2418R2>`__","LWG","Add support for ``std::generator``-like types to ``std::format``","October 2021","|Complete|","15.0"
 "`P2432R1 <https://wg21.link/P2432R1>`__","LWG","Fix ``istream_view``","October 2021","",""

diff  --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index a406edb04a8b2..e5128322aed97 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -161,4 +161,5 @@
 "","","","",""
 "`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","Not voted in","|Complete|","14.0",""
 "`3656 <https://wg21.link/LWG3656>`__","Inconsistent bit operations returning a count","Not voted in","|Complete|","15.0",""
+"`3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","Not voted in","|Complete|","15.0",""
 "","","","",""

diff  --git a/libcxx/include/__format/format_arg.h b/libcxx/include/__format/format_arg.h
index 3f2afc898d2c6..4f93024b7c697 100644
--- a/libcxx/include/__format/format_arg.h
+++ b/libcxx/include/__format/format_arg.h
@@ -147,15 +147,20 @@ class __basic_format_arg_value {
   /// Contains the implementation for basic_format_arg::handle.
   struct __handle {
     template <class _Tp>
-    _LIBCPP_HIDE_FROM_ABI explicit __handle(const _Tp& __v) noexcept
+    _LIBCPP_HIDE_FROM_ABI explicit __handle(_Tp&& __v) noexcept
         : __ptr_(_VSTD::addressof(__v)),
           __format_([](basic_format_parse_context<_CharT>& __parse_ctx, _Context& __ctx, const void* __ptr) {
-            using _Formatter = typename _Context::template formatter_type<_Tp>;
-            using _Qp = conditional_t<requires { _Formatter().format(declval<const _Tp&>(), declval<_Context&>()); },
-                                      const _Tp, _Tp>;
+            using _Dp = remove_cvref_t<_Tp>;
+            using _Formatter = typename _Context::template formatter_type<_Dp>;
+            constexpr bool __const_formattable =
+                requires { _Formatter().format(declval<const _Dp&>(), declval<_Context&>()); };
+            using _Qp = conditional_t<__const_formattable, const _Dp, _Dp>;
+
+            static_assert(__const_formattable || !is_const_v<remove_reference_t<_Tp>>, "Mandated by [format.arg]/18");
+
             _Formatter __f;
             __parse_ctx.advance_to(__f.parse(__parse_ctx));
-            __ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Tp*>(__ptr)), __ctx));
+            __ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Dp*>(__ptr)), __ctx));
           }) {}
 
     const void* __ptr_;
@@ -205,7 +210,9 @@ class __basic_format_arg_value {
   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(basic_string_view<_CharT> __value) noexcept
       : __string_view_(__value) {}
   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const void* __value) noexcept : __ptr_(__value) {}
-  _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle __value) noexcept : __handle_(__value) {}
+  _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle __value) noexcept
+      // TODO FMT Investigate why it doesn't work without the forward.
+      : __handle_(std::forward<__handle>(__value)) {}
 };
 
 template <class _Context>
@@ -251,11 +258,11 @@ class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle {
     __handle_.__format_(__parse_ctx, __ctx, __handle_.__ptr_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI explicit handle(typename __basic_format_arg_value<_Context>::__handle __handle) noexcept
+  _LIBCPP_HIDE_FROM_ABI explicit handle(typename __basic_format_arg_value<_Context>::__handle& __handle) noexcept
       : __handle_(__handle) {}
 
 private:
-  typename __basic_format_arg_value<_Context>::__handle __handle_;
+  typename __basic_format_arg_value<_Context>::__handle& __handle_;
 };
 
 #endif //_LIBCPP_STD_VER > 17

diff  --git a/libcxx/include/__format/format_arg_store.h b/libcxx/include/__format/format_arg_store.h
index 6602dfeb956b2..26a5e71b93af6 100644
--- a/libcxx/include/__format/format_arg_store.h
+++ b/libcxx/include/__format/format_arg_store.h
@@ -197,7 +197,7 @@ _LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_fo
   int __shift = 0;
   (
       [&] {
-        basic_format_arg<_Context> __arg = __create_format_arg<_Context>(_VSTD::forward<_Args>(__args));
+        basic_format_arg<_Context> __arg = __create_format_arg<_Context>(__args);
         if (__shift != 0)
           __types |= static_cast<uint64_t>(__arg.__type_) << __shift;
         else
@@ -211,7 +211,7 @@ _LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_fo
 
 template <class _Context, class... _Args>
 _LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&&... __args) noexcept {
-  ([&] { *__data++ = __create_format_arg<_Context>(_VSTD::forward<_Args>(__args)); }(), ...);
+  ([&] { *__data++ = __create_format_arg<_Context>(__args); }(), ...);
 }
 
 template <class _Context, size_t N>
@@ -230,12 +230,12 @@ struct __unpacked_format_arg_store {
 template <class _Context, class... _Args>
 struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
   _LIBCPP_HIDE_FROM_ABI
-  __format_arg_store(_Args&&... __args) noexcept {
+  __format_arg_store(_Args&... __args) noexcept {
     if constexpr (sizeof...(_Args) != 0) {
       if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args)))
-        __format::__create_packed_storage(__storage.__types_, __storage.__values_, _VSTD::forward<_Args>(__args)...);
+        __format::__create_packed_storage(__storage.__types_, __storage.__values_, __args...);
       else
-        __format::__store_basic_format_arg<_Context>(__storage.__args_, _VSTD::forward<_Args>(__args)...);
+        __format::__store_basic_format_arg<_Context>(__storage.__args_, __args...);
     }
   }
 

diff  --git a/libcxx/include/format b/libcxx/include/format
index bf51edd91ecec..dd7d08dbbe0b0 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -36,13 +36,13 @@ namespace std {
 
   // [format.functions], formatting functions
   template<class... Args>
-    string format(format-string<Args...> fmt, const Args&... args);
+    string format(format-string<Args...> fmt, Args&&... args);
   template<class... Args>
-    wstring format(wformat-string<Args...> fmt, const Args&... args);
+    wstring format(wformat-string<Args...> fmt, Args&&... args);
   template<class... Args>
-    string format(const locale& loc, format-string<Args...> fmt, const Args&... args);
+    string format(const locale& loc, format-string<Args...> fmt, Args&&... args);
   template<class... Args>
-    wstring format(const locale& loc, wformat-string<Args...> fmt, const Args&... args);
+    wstring format(const locale& loc, wformat-string<Args...> fmt, Args&&... args);
 
   string vformat(string_view fmt, format_args args);
   wstring vformat(wstring_view fmt, wformat_args args);
@@ -50,13 +50,13 @@ namespace std {
   wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
 
   template<class Out, class... Args>
-    Out format_to(Out out, format-string<Args...> fmt, const Args&... args);
+    Out format_to(Out out, format-string<Args...> fmt, Args&&... args);
   template<class Out, class... Args>
-    Out format_to(Out out, wformat-string<Args...> fmt, const Args&... args);
+    Out format_to(Out out, wformat-string<Args...> fmt, Args&&... args);
   template<class Out, class... Args>
-    Out format_to(Out out, const locale& loc, format-string<Args...> fmt, const Args&... args);
+    Out format_to(Out out, const locale& loc, format-string<Args...> fmt, Args&&... args);
   template<class Out, class... Args>
-    Out format_to(Out out, const locale& loc, wformat-string<Args...> fmt, const Args&... args);
+    Out format_to(Out out, const locale& loc, wformat-string<Args...> fmt, Args&&... args);
 
   template<class Out>
     Out vformat_to(Out out, string_view fmt, format_args args);
@@ -75,27 +75,27 @@ namespace std {
   };
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
-                                        format-string<Args...> fmt, const Args&... args);
+                                        format-string<Args...> fmt, Args&&... args);
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
-                                        wformat-string<Args...> fmt, const Args&... args);
+                                        wformat-string<Args...> fmt, Args&&... args);
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
                                         const locale& loc, format-string<Args...> fmt,
-                                        const Args&... args);
+                                        Args&&... args);
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
                                         const locale& loc, wformat-string<Args...> fmt,
-                                        const Args&... args);
+                                        Args&&... args);
 
   template<class... Args>
-    size_t formatted_size(format-string<Args...> fmt, const Args&... args);
+    size_t formatted_size(format-string<Args...> fmt, Args&&... args);
   template<class... Args>
-    size_t formatted_size(wformat-string<Args...> fmt, const Args&... args);
+    size_t formatted_size(wformat-string<Args...> fmt, Args&&... args);
   template<class... Args>
-    size_t formatted_size(const locale& loc, format-string<Args...> fmt, const Args&... args);
+    size_t formatted_size(const locale& loc, format-string<Args...> fmt, Args&&... args);
   template<class... Args>
-    size_t formatted_size(const locale& loc, wformat-string<Args...> fmt, const Args&... args);
+    size_t formatted_size(const locale& loc, wformat-string<Args...> fmt, Args&&... args);
 
   // [format.formatter], formatter
   template<class T, class charT = char> struct formatter;
@@ -117,10 +117,10 @@ namespace std {
 
   template<class Context = format_context, class... Args>
     format-arg-store<Context, Args...>
-      make_format_args(const Args&... args);
+      make_format_args(Args&&... args);
   template<class... Args>
     format-arg-store<wformat_context, Args...>
-      make_wformat_args(const Args&... args);
+      make_wformat_args(Args&&... args);
 
   // [format.error], class format_error
   class format_error;
@@ -190,26 +190,15 @@ using format_args = basic_format_args<format_context>;
 using wformat_args = basic_format_args<wformat_context>;
 #endif
 
-// TODO FMT This helper wrapper can probably be removed after P2418 has been
-// implemented.
-template <class _Context, class... _Args>
-_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...>
-__make_format_args(_Args&&... __args) {
-  return _VSTD::__format_arg_store<_Context, _Args...>(
-      _VSTD::forward<_Args>(__args)...);
-}
-
-// TODO FMT After P2418 specify the return type instead of using auto.
 template <class _Context = format_context, class... _Args>
-_LIBCPP_HIDE_FROM_ABI auto make_format_args(const _Args&... __args) {
-  return _VSTD::__make_format_args<_Context>(__args...);
+_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
+  return _VSTD::__format_arg_store<_Context, _Args...>(__args...);
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-// TODO FMT After P2418 specify the return type instead of using auto.
 template <class... _Args>
-_LIBCPP_HIDE_FROM_ABI auto make_wformat_args(const _Args&... __args) {
-  return _VSTD::make_format_args<wformat_context>(__args...);
+_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&&... __args) {
+  return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...);
 }
 #endif
 
@@ -563,7 +552,7 @@ vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, __format_string_t<_Args...> __fmt, const _Args&... __args) {
+format_to(_OutIt __out_it, __format_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_,
                            _VSTD::make_format_args(__args...));
 }
@@ -571,7 +560,7 @@ format_to(_OutIt __out_it, __format_string_t<_Args...> __fmt, const _Args&... __
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, __wformat_string_t<_Args...> __fmt, const _Args&... __args) {
+format_to(_OutIt __out_it, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_,
                            _VSTD::make_wformat_args(__args...));
 }
@@ -595,14 +584,14 @@ vformat(wstring_view __fmt, wformat_args __args) {
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(__format_string_t<_Args...> __fmt,
-                                                                                      const _Args&... __args) {
+                                                                                      _Args&&... __args) {
   return _VSTD::vformat(__fmt.__str_, _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-format(__wformat_string_t<_Args...> __fmt, const _Args&... __args) {
+format(__wformat_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::vformat(__fmt.__str_, _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -619,7 +608,7 @@ _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it,
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, __format_string_t<_Args...> __fmt, const _Args&... __args) {
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, __format_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_format_args(__args...));
 }
 
@@ -627,7 +616,7 @@ format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, __format_string_t<_A
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
 format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, __wformat_string_t<_Args...> __fmt,
-            const _Args&... __args) {
+            _Args&&... __args) {
   return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -642,14 +631,14 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt,
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(__format_string_t<_Args...> __fmt, const _Args&... __args) {
+formatted_size(__format_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)});
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(__wformat_string_t<_Args...> __fmt, const _Args&... __args) {
+formatted_size(__wformat_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)});
 }
 #endif
@@ -694,7 +683,7 @@ _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt v
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, locale __loc, __format_string_t<_Args...> __fmt, const _Args&... __args) {
+format_to(_OutIt __out_it, locale __loc, __format_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_,
                            _VSTD::make_format_args(__args...));
 }
@@ -702,7 +691,7 @@ format_to(_OutIt __out_it, locale __loc, __format_string_t<_Args...> __fmt, cons
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, locale __loc, __wformat_string_t<_Args...> __fmt, const _Args&... __args) {
+format_to(_OutIt __out_it, locale __loc, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_,
                            _VSTD::make_wformat_args(__args...));
 }
@@ -729,7 +718,7 @@ vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(locale __loc,
                                                                                       __format_string_t<_Args...> __fmt,
-                                                                                      const _Args&... __args) {
+                                                                                      _Args&&... __args) {
   return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_,
                         _VSTD::make_format_args(__args...));
 }
@@ -737,7 +726,7 @@ _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string f
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-format(locale __loc, __wformat_string_t<_Args...> __fmt, const _Args&... __args) {
+format(locale __loc, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_,
                         _VSTD::make_wformat_args(__args...));
 }
@@ -757,7 +746,7 @@ _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it,
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
 format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, __format_string_t<_Args...> __fmt,
-            const _Args&... __args) {
+            _Args&&... __args) {
   return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_,
                                                _VSTD::make_format_args(__args...));
 }
@@ -766,7 +755,7 @@ format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, __form
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
 format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, __wformat_string_t<_Args...> __fmt,
-            const _Args&... __args) {
+            _Args&&... __args) {
   return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_,
                                                 _VSTD::make_wformat_args(__args...));
 }
@@ -783,14 +772,14 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(locale __loc, __format_string_t<_Args...> __fmt, const _Args&... __args) {
+formatted_size(locale __loc, __format_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)});
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(locale __loc, __wformat_string_t<_Args...> __fmt, const _Args&... __args) {
+formatted_size(locale __loc, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
   return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)});
 }
 #endif

diff  --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
index 753b27f4efc5e..2e602428df484 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
@@ -22,9 +22,10 @@
 #include "test_macros.h"
 
 int main(int, char**) {
-  using Context [[maybe_unused]] = std::basic_format_context< std::back_insert_iterator<std::basic_string<char>>, char>;
+  [[maybe_unused]] auto store = std::make_format_args(42, nullptr, false, 1.0);
 
-  std::make_format_args(42, nullptr, false, 1.0);
+  LIBCPP_STATIC_ASSERT(
+      std::same_as<decltype(store), std::__format_arg_store<std::format_context, int, nullptr_t, bool, double>>);
 
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
index 62fa5fa882343..14328a1425d08 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
@@ -22,10 +22,10 @@
 #include "test_macros.h"
 
 int main(int, char**) {
-  using Context [[maybe_unused]] =
-      std::basic_format_context<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>;
+  [[maybe_unused]] auto store = std::make_wformat_args(42, nullptr, false, 1.0);
 
-  std::make_wformat_args(42, nullptr, false, 1.0);
+  LIBCPP_STATIC_ASSERT(
+      std::same_as<decltype(store), std::__format_arg_store<std::wformat_context, int, nullptr_t, bool, double>>);
 
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp b/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp
new file mode 100644
index 0000000000000..1ccade8e542c2
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp
@@ -0,0 +1,126 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// Tests whether a move only type can be formatted. This is required by
+// P2418R2 "Add support for std::generator-like types to std::format"
+
+// <format>
+
+#include <format>
+#include <cassert>
+
+#include "MoveOnly.h"
+#include "make_string.h"
+#include "test_macros.h"
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+#  include <locale>
+#endif
+
+#define SV(S) MAKE_STRING_VIEW(CharT, S)
+
+template <class CharT>
+struct std::formatter<MoveOnly, CharT> : std::formatter<int, CharT> {
+  // TODO FMT Make this a const member function after the base class has been adapted.
+  auto format(const MoveOnly& m, auto& ctx) -> decltype(ctx.out()) {
+    return std::formatter<int, CharT>::format(m.get(), ctx);
+  }
+};
+
+template <class CharT>
+static void test() {
+  MoveOnly m{10};
+  CharT buffer[10];
+#ifndef TEST_HAS_NO_LOCALIZATION
+  std::locale loc;
+#endif
+
+  assert(std::format(SV("{}"), MoveOnly{}) == SV("1"));
+
+  assert(std::format(SV("{}"), m) == SV("10"));
+  assert(m.get() == 10);
+
+  assert(std::format(SV("{}"), std::move(m)) == SV("10"));
+  assert(m.get() == 10);
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+  assert(std::format(loc, SV("{}"), MoveOnly{}) == SV("1"));
+
+  assert(std::format(loc, SV("{}"), m) == SV("10"));
+  assert(m.get() == 10);
+
+  assert(std::format(loc, SV("{}"), std::move(m)) == SV("10"));
+  assert(m.get() == 10);
+#endif
+
+  assert(std::format_to(buffer, SV("{}"), MoveOnly{}) == &buffer[1]);
+
+  assert(std::format_to(buffer, SV("{}"), m) == &buffer[2]);
+  assert(m.get() == 10);
+
+  assert(std::format_to(buffer, SV("{}"), std::move(m)) == &buffer[2]);
+  assert(m.get() == 10);
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+  assert(std::format_to(buffer, loc, SV("{}"), MoveOnly{}) == &buffer[1]);
+
+  assert(std::format_to(buffer, loc, SV("{}"), m) == &buffer[2]);
+  assert(m.get() == 10);
+
+  assert(std::format_to(buffer, loc, SV("{}"), std::move(m)) == &buffer[2]);
+  assert(m.get() == 10);
+#endif
+
+  assert(std::format_to_n(buffer, 5, SV("{}"), MoveOnly{}).out == &buffer[1]);
+
+  assert(std::format_to_n(buffer, 5, SV("{}"), m).out == &buffer[2]);
+  assert(m.get() == 10);
+
+  assert(std::format_to_n(buffer, 5, SV("{}"), std::move(m)).out == &buffer[2]);
+  assert(m.get() == 10);
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+  assert(std::format_to_n(buffer, 5, loc, SV("{}"), MoveOnly{}).out == &buffer[1]);
+
+  assert(std::format_to_n(buffer, 5, loc, SV("{}"), m).out == &buffer[2]);
+  assert(m.get() == 10);
+
+  assert(std::format_to_n(buffer, 5, loc, SV("{}"), std::move(m)).out == &buffer[2]);
+  assert(m.get() == 10);
+#endif
+
+  assert(std::formatted_size(SV("{}"), MoveOnly{}) == 1);
+
+  assert(std::formatted_size(SV("{}"), m) == 2);
+  assert(m.get() == 10);
+
+  assert(std::formatted_size(SV("{}"), std::move(m)) == 2);
+  assert(m.get() == 10);
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+  assert(std::formatted_size(loc, SV("{}"), MoveOnly{}) == 1);
+
+  assert(std::formatted_size(loc, SV("{}"), m) == 2);
+  assert(m.get() == 10);
+
+  assert(std::formatted_size(loc, SV("{}"), std::move(m)) == 2);
+  assert(m.get() == 10);
+#endif
+}
+
+int main(int, char**) {
+  test<char>();
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format.verify.cpp
index 0febf0e073f4c..48476a9e2599d 100644
--- a/libcxx/test/std/utilities/format/format.functions/format.verify.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.verify.cpp
@@ -88,3 +88,17 @@ void f() {
   // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
 #endif
 }
+
+struct tiny {
+  int bit : 1;
+};
+
+void P2418()
+{
+	auto t = tiny{};
+	std::format("{}", t.bit); // expected-error{{non-const reference cannot bind to bit-field 'bit'}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+	std::format(L"{}", t.bit); // expected-error{{non-const reference cannot bind to bit-field 'bit'}}
+#endif
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h
index 6a019d06fd4e1..5ca54bdc1b319 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -2518,6 +2518,11 @@ void format_test_handle(TestFunction check, ExceptionTest check_exception) {
   check.template operator()<"answer is '{:X}'">(SV("answer is '0XAA55'"), status::foobar);
   check.template operator()<"answer is '{:s}'">(SV("answer is 'foobar'"), status::foobar);
 
+  // P2418 Changed the argument from a const reference to a forwarding reference.
+  // This mainly affects handle classes, however since we use an abstraction
+  // layer here it's "tricky" to verify whether this test would do the "right"
+  // thing. So these tests are done separately.
+
   // *** type ***
   for (const auto& fmt : invalid_types<CharT>("xXs"))
     check_exception("The format-spec type has a type not supported for a status argument", fmt, status::foo);


        


More information about the libcxx-commits mailing list