forked from OSchip/llvm-project
[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
This commit is contained in:
parent
c4ccf608c2
commit
606e280811
|
@ -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
|
||||
-----------
|
||||
|
|
|
@ -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","",""
|
||||
|
|
|
|
@ -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",""
|
||||
"","","","",""
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
@ -147,15 +147,20 @@ public:
|
|||
/// 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 @@ public:
|
|||
_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 @@ public:
|
|||
__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
|
||||
|
|
|
@ -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...);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_difference_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_difference_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_difference_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_difference_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_difference_t<_OutIt> __n, __format_string_t<_Args...> __fmt, const _Args&... __args) {
|
||||
format_to_n(_OutIt __out_it, iter_difference_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_difference_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_difference_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_difference_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_difference_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_difference_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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue