diff --git a/libcxx/benchmarks/formatter_float.bench.cpp b/libcxx/benchmarks/formatter_float.bench.cpp --- a/libcxx/benchmarks/formatter_float.bench.cpp +++ b/libcxx/benchmarks/formatter_float.bench.cpp @@ -216,17 +216,27 @@ void run(benchmark::State& state) const { std::array data{Value::template make_data()}; std::array output; - std::string fmt{std::string("{:") + Alignment::fmt + Precision::fmt + - Localization::fmt + DisplayType::fmt + "}"}; while (state.KeepRunningBatch(1000)) for (F value : data) - benchmark::DoNotOptimize(std::format_to(output.begin(), fmt, value)); + benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value)); } std::string name() const { return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name(); } + + static constexpr std::string make_fmt() { + return std::string("{:") + Alignment::fmt + Precision::fmt + Localization::fmt + + DisplayType::fmt + "}"; + } + + static constexpr auto fmt = []() { + constexpr size_t s = make_fmt().size(); + std::array r; + std::ranges::copy(make_fmt(), r.begin()); + return r; + }(); }; int main(int argc, char** argv) { diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -73,6 +73,14 @@ moved from the dylib to the header. This means the function no longer has a minimum deployment target. +- Implemented P2216R3 (std::format improvements). The format functions + (``std::format``, ``std::format_to``, ``std::format_to_n``, and + ``std::formatted_size``) now validate the format string at compile time. + When the format string is invalid this will make the code ill-formed instead + of throwing an exception at run-time. (This does not affect the ``v`` + functions.) + + API Changes ----------- diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -196,7 +196,7 @@ "`P2231R1 `__","LWG","Missing constexpr in std::optional and std::variant","June 2021","|Partial| [#note-P2231]_","13.0" "`P2325R3 `__","LWG","Views should not be required to be default constructible","June 2021","|In progress|","" "`P2210R2 `__","LWG",Superior String Splitting,"June 2021","","" -"`P2216R3 `__","LWG",std::format improvements,"June 2021","|Partial|","" +"`P2216R3 `__","LWG",std::format improvements,"June 2021","|Complete|","15.0" "`P2281R1 `__","LWG",Clarifying range adaptor objects,"June 2021","|Complete|","14.0" "`P2328R1 `__","LWG",join_view should join all views of ranges,"June 2021","","" "`P2367R0 `__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","","" diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h --- a/libcxx/include/__format/parser_std_format_spec.h +++ b/libcxx/include/__format/parser_std_format_spec.h @@ -252,25 +252,21 @@ /** Determines whether the value stored is a width or an arg-id. */ uint32_t __width_as_arg : 1 {0}; -protected: /** - * Does the supplied std-format-spec contain a width field? + * Does the supplied width field contain an arg-id? * - * When the field isn't present there's no padding required. This can be used - * to optimize the formatting. + * If @c true the formatter needs to call @ref __substitute_width_arg_id. */ - constexpr bool __has_width_field() const noexcept { - return __width_as_arg || __width; - } + constexpr bool __width_needs_substitution() const noexcept { return __width_as_arg; } +protected: /** - * Does the supplied width field contain an arg-id? + * Does the supplied std-format-spec contain a width field? * - * If @c true the formatter needs to call @ref __substitute_width_arg_id. + * When the field isn't present there's no padding required. This can be used + * to optimize the formatting. */ - constexpr bool __width_needs_substitution() const noexcept { - return __width_as_arg; - } + constexpr bool __has_width_field() const noexcept { return __width_as_arg || __width; } template _LIBCPP_HIDE_FROM_ABI constexpr const _CharT* @@ -327,6 +323,15 @@ */ uint32_t __precision_as_arg : 1 {1}; + /** + * Does the supplied precision field contain an arg-id? + * + * If @c true the formatter needs to call @ref __substitute_precision_arg_id. + */ + constexpr bool __precision_needs_substitution() const noexcept { + return __precision_as_arg && __precision != __format::__number_max; + } + protected: /** * Does the supplied std-format-spec contain a precision field? @@ -340,15 +345,6 @@ __precision != __format::__number_max; // The arg-id is valid? } - /** - * Does the supplied precision field contain an arg-id? - * - * If @c true the formatter needs to call @ref __substitute_precision_arg_id. - */ - constexpr bool __precision_needs_substitution() const noexcept { - return __precision_as_arg && __precision != __format::__number_max; - } - template _LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __parse(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) { diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -23,15 +23,26 @@ using format_args = basic_format_args; using wformat_args = basic_format_args; + // [format.fmt.string], class template basic-format-string + template + struct basic-format-string; // exposition only + + template + using format-string = // exposition only + basic-format-string...>; + template + using wformat-string = // exposition only + basic-format-string...>; + // [format.functions], formatting functions template - string format(string_view fmt, const Args&... args); + string format(format-string fmt, const Args&... args); template - wstring format(wstring_view fmt, const Args&... args); + wstring format(wformat-string fmt, const Args&... args); template - string format(const locale& loc, string_view fmt, const Args&... args); + string format(const locale& loc, format-string fmt, const Args&... args); template - wstring format(const locale& loc, wstring_view fmt, const Args&... args); + wstring format(const locale& loc, wformat-string fmt, const Args&... args); string vformat(string_view fmt, format_args args); wstring vformat(wstring_view fmt, wformat_args args); @@ -39,13 +50,13 @@ wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); template - Out format_to(Out out, string_view fmt, const Args&... args); + Out format_to(Out out, format-string fmt, const Args&... args); template - Out format_to(Out out, wstring_view fmt, const Args&... args); + Out format_to(Out out, wformat-string fmt, const Args&... args); template - Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args); + Out format_to(Out out, const locale& loc, format-string fmt, const Args&... args); template - Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args); + Out format_to(Out out, const locale& loc, wformat-string fmt, const Args&... args); template Out vformat_to(Out out, string_view fmt, format_args args); @@ -64,27 +75,27 @@ }; template format_to_n_result format_to_n(Out out, iter_difference_t n, - string_view fmt, const Args&... args); + format-string fmt, const Args&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - wstring_view fmt, const Args&... args); + wformat-string fmt, const Args&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - const locale& loc, string_view fmt, + const locale& loc, format-string fmt, const Args&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - const locale& loc, wstring_view fmt, + const locale& loc, wformat-string fmt, const Args&... args); template - size_t formatted_size(string_view fmt, const Args&... args); + size_t formatted_size(format-string fmt, const Args&... args); template - size_t formatted_size(wstring_view fmt, const Args&... args); + size_t formatted_size(wformat-string fmt, const Args&... args); template - size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); + size_t formatted_size(const locale& loc, format-string fmt, const Args&... args); template - size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args); + size_t formatted_size(const locale& loc, wformat-string fmt, const Args&... args); // [format.formatter], formatter template struct formatter; @@ -203,8 +214,163 @@ namespace __format { +/// Helper class parse and handle argument. +/// +/// When parsing a handle which is not enabled the code is ill-formed. +/// This helper uses the parser of the appropriate formatter for the stored type. +template +class _LIBCPP_TEMPLATE_VIS __compile_time_handle { +public: + _LIBCPP_HIDE_FROM_ABI + constexpr void __parse(basic_format_parse_context<_CharT>& __parse_ctx) const { __parse_(__parse_ctx); } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __enable() { + __parse_ = [](basic_format_parse_context<_CharT>& __parse_ctx) { + formatter<_Tp, _CharT> __f; + __parse_ctx.advance_to(__f.parse(__parse_ctx)); + }; + } + + // Before calling __parse the proper handler needs to be set with __enable. + // The default handler isn't a core constant expression. + _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle() + : __parse_([](basic_format_parse_context<_CharT>&) { __throw_format_error("Not a handle"); }) {} + +private: + void (*__parse_)(basic_format_parse_context<_CharT>&); +}; + +// Dummy format_context only providing the parts used during constant +// validation of the basic-format-string. +template +struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context { +public: + using char_type = _CharT; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context( + const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size) + : __args_(__args), __handles_(__handles), __size_(__size) {} + + // During the compile-time validation nothing needs to be written. + // Therefore all operations of this iterator are a NOP. + struct iterator { + _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; } + }; + + _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const { + if (__id >= __size_) + __throw_format_error("Argument index out of bounds"); + return __args_[__id]; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const { + if (__id >= __size_) + __throw_format_error("Argument index out of bounds"); + return __handles_[__id]; + } + + _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; } + _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {} + +private: + const __arg_t* __args_; + const __compile_time_handle<_CharT>* __handles_; + size_t __size_; +}; + +_LIBCPP_HIDE_FROM_ABI +constexpr void __compile_time_validate_integral(__arg_t __type) { + switch (__type) { + case __arg_t::__int: + case __arg_t::__long_long: + case __arg_t::__i128: + case __arg_t::__unsigned: + case __arg_t::__unsigned_long_long: + case __arg_t::__u128: + return; + + default: + __throw_format_error("Argument isn't an integral type"); + } +} + +// _HasPrecision does the formatter have a precision? +template +_LIBCPP_HIDE_FROM_ABI constexpr void +__compile_time_validate_argument(basic_format_parse_context<_CharT>& __parse_ctx, + __compile_time_basic_format_context<_CharT>& __ctx) { + formatter<_Tp, _CharT> __formatter; + __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); + // [format.string.std]/7 + // ... If the corresponding formatting argument is not of integral type, or + // its value is negative for precision or non-positive for width, an + // exception of type format_error is thrown. + // + // Validate whether the arguments are integrals. + if (__formatter.__width_needs_substitution()) + __format::__compile_time_validate_integral(__ctx.arg(__formatter.__width)); + + if constexpr (_HasPrecision) + if (__formatter.__precision_needs_substitution()) + __format::__compile_time_validate_integral(__ctx.arg(__formatter.__precision)); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_format_parse_context<_CharT>& __parse_ctx, + __compile_time_basic_format_context<_CharT>& __ctx, + __arg_t __type) { + switch (__type) { + case __arg_t::__none: + __throw_format_error("Invalid argument"); + case __arg_t::__boolean: + return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx); + case __arg_t::__char_type: + return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx); + case __arg_t::__int: + return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx); + case __arg_t::__long_long: + return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx); + case __arg_t::__i128: +# ifndef _LIBCPP_HAS_NO_INT128 + return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx); +# else + __throw_format_error("Invalid argument"); +# endif + return; + case __arg_t::__unsigned: + return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx); + case __arg_t::__unsigned_long_long: + return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx); + case __arg_t::__u128: +# ifndef _LIBCPP_HAS_NO_INT128 + return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx); +# else + __throw_format_error("Invalid argument"); +# endif + return; + case __arg_t::__float: + return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx); + case __arg_t::__double: + return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx); + case __arg_t::__long_double: + return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx); + case __arg_t::__const_char_type_ptr: + return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx); + case __arg_t::__string_view: + return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx); + case __arg_t::__ptr: + return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx); + case __arg_t::__handle: + __throw_format_error("Handle should use __compile_time_validate_handle_argument"); + } + __throw_format_error("Invalid argument"); +} + template -_LIBCPP_HIDE_FROM_ABI const _CharT* +_LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __handle_replacement_field(const _CharT* __begin, const _CharT* __end, _ParseCtx& __parse_ctx, _Ctx& __ctx) { __format::__parse_number_result __r = @@ -224,19 +390,26 @@ "The replacement field arg-id should terminate at a ':' or '}'"); } - _VSTD::visit_format_arg( - [&](auto __arg) { - if constexpr (same_as) - __throw_format_error("Argument index out of bounds"); - else if constexpr (same_as::handle>) - __arg.format(__parse_ctx, __ctx); - else { - formatter __formatter; - __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); - __ctx.advance_to(__formatter.format(__arg, __ctx)); - } - }, - __ctx.arg(__r.__value)); + if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) { + __arg_t __type = __ctx.arg(__r.__value); + if (__type == __arg_t::__handle) + __ctx.__handle(__r.__value).__parse(__parse_ctx); + else + __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type); + } else + _VSTD::visit_format_arg( + [&](auto __arg) { + if constexpr (same_as) + __throw_format_error("Argument index out of bounds"); + else if constexpr (same_as::handle>) + __arg.format(__parse_ctx, __ctx); + else { + formatter __formatter; + __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); + __ctx.advance_to(__formatter.format(__arg, __ctx)); + } + }, + __ctx.arg(__r.__value)); __begin = __parse_ctx.begin(); if (__begin == __end || *__begin != _CharT('}')) @@ -246,7 +419,7 @@ } template -_LIBCPP_HIDE_FROM_ABI typename _Ctx::iterator +_LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) { using _CharT = typename _ParseCtx::char_type; static_assert(same_as); @@ -291,6 +464,56 @@ } // namespace __format +template +struct _LIBCPP_TEMPLATE_VIS __basic_format_string { + basic_string_view<_CharT> __str_; + + template + requires convertible_to> + consteval __basic_format_string(const _Tp& __str) : __str_{__str} { + __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)}, + _Context{__types_.data(), __handles_.data(), sizeof...(_Args)}); + } + +private: + using _Context = __format::__compile_time_basic_format_context<_CharT>; + + static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{ + __format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...}; + + // TODO FMT remove this work-around when the AIX ICE has been resolved. +# if defined(_AIX) && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 1400 + template + static constexpr __format::__compile_time_handle<_CharT> __get_handle() { + __format::__compile_time_handle<_CharT> __handle; + if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) + __handle.template __enable<_Tp>(); + + return __handle; + } + + static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{ + __get_handle<_Args>()...}; +# else + static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] { + using _Tp = remove_cvref_t<_Args>; + __format::__compile_time_handle<_CharT> __handle; + if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) + __handle.template __enable<_Tp>(); + + return __handle; + }()...}; +# endif +}; + +template +using __format_string_t = __basic_format_string...>; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +using __wformat_string_t = __basic_format_string...>; +#endif + template requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to( @@ -329,16 +552,16 @@ template _OutIt, class... _Args> _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt -format_to(_OutIt __out_it, string_view __fmt, const _Args&... __args) { - return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt, +format_to(_OutIt __out_it, __format_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_, _VSTD::make_format_args(__args...)); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _OutIt, class... _Args> _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt -format_to(_OutIt __out_it, wstring_view __fmt, const _Args&... __args) { - return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt, +format_to(_OutIt __out_it, __wformat_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -360,16 +583,16 @@ #endif template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string -format(string_view __fmt, const _Args&... __args) { - return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(__format_string_t<_Args...> __fmt, + const _Args&... __args) { + return _VSTD::vformat(__fmt.__str_, _VSTD::make_format_args(__args...)); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring -format(wstring_view __fmt, const _Args&... __args) { - return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)); +format(__wformat_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::vformat(__fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -385,15 +608,16 @@ template _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, string_view __fmt, const _Args&... __args) { - return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, __fmt, _VSTD::make_format_args(__args...)); +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, __format_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_format_args(__args...)); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _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, wstring_view __fmt, const _Args&... __args) { - return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, __fmt, _VSTD::make_wformat_args(__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) { + return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -406,16 +630,16 @@ } template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(string_view __fmt, - const _Args&... __args) { - return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_format_args(__args...)}); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t +formatted_size(__format_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)}); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(wstring_view __fmt, - const _Args&... __args) { - return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_wformat_args(__args...)}); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t +formatted_size(__wformat_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)}); } #endif @@ -458,17 +682,17 @@ #endif template _OutIt, class... _Args> -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to( - _OutIt __out_it, locale __loc, string_view __fmt, const _Args&... __args) { - return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, +_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) { + return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_, _VSTD::make_format_args(__args...)); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _OutIt, class... _Args> -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to( - _OutIt __out_it, locale __loc, wstring_view __fmt, const _Args&... __args) { - return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, +_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) { + return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -492,17 +716,18 @@ #endif template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string -format(locale __loc, string_view __fmt, const _Args&... __args) { - return _VSTD::vformat(_VSTD::move(__loc), __fmt, +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(locale __loc, + __format_string_t<_Args...> __fmt, + const _Args&... __args) { + return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_, _VSTD::make_format_args(__args...)); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring -format(locale __loc, wstring_view __fmt, const _Args&... __args) { - return _VSTD::vformat(_VSTD::move(__loc), __fmt, +format(locale __loc, __wformat_string_t<_Args...> __fmt, const _Args&... __args) { + return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -520,16 +745,18 @@ template _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, string_view __fmt, const _Args&... __args) { - return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt, +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, __format_string_t<_Args...> __fmt, + const _Args&... __args) { + return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_, _VSTD::make_format_args(__args...)); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _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, wstring_view __fmt, const _Args&... __args) { - return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt, +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, __wformat_string_t<_Args...> __fmt, + const _Args&... __args) { + return _VSTD::__vformat_to_n(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -544,18 +771,16 @@ } template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc, - string_view __fmt, - const _Args&... __args) { - return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_format_args(__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) { + return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)}); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc, - wstring_view __fmt, - const _Args&... __args) { - return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_wformat_args(__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) { + 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.functions/format.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp @@ -16,9 +16,9 @@ // // template -// string format(const locale& loc, string_view fmt, const Args&... args); +// string format(const locale& loc, format-string fmt, const Args&... args); // template -// wstring format(const locale& loc, wstring_view fmt, const Args&... args); +// wstring format(const locale& loc, wformat-string fmt, const Args&... args); #include #include @@ -39,30 +39,11 @@ assert(out == expected); }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::format(std::locale(), fmt, args...); - if constexpr (std::same_as) - std::cerr << "\nFormat string " << fmt << "\nDidn't throw an exception.\n"; - assert(false); - } catch (const std::format_error& e) { -# ifdef _LIBCPP_VERSION - if constexpr (std::same_as) - if (e.what() != what) - std::cerr << "\nFormat string " << fmt << "\nExpected exception " << what << "\nActual exception " - << e.what() << '\n'; -# endif - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::format become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in format.locale.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/format.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/format.locale.verify.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// 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: no-localization +// UNSUPPORTED: libcpp-has-no-incomplete-format +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// string format(const locale& loc, format-string fmt, const Args&... args); +// template +// wstring format(const locale& loc, wformat-string fmt, const Args&... args); + +#include +#include + +#include "test_macros.h" + +// clang-format off + +void f() { + std::format(std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::format(std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp @@ -19,9 +19,9 @@ // // template -// string format(string_view fmt, const Args&... args); +// string format(format-string fmt, const Args&... args); // template -// wstring format(wstring_view fmt, const Args&... args); +// wstring format(wformat-string fmt, const Args&... args); #include #include @@ -48,31 +48,11 @@ assert(out == expected); }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::format(fmt, args...); -# ifndef TEST_HAS_NO_LOCALIZATION - if constexpr (std::same_as) - std::cerr << "\nFormat string " << fmt << "\nDidn't throw an exception.\n"; -# endif - assert(false); - } catch (const std::format_error& e) { - if constexpr (std::same_as) -# if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_LOCALIZATION) - if (e.what() != what) - std::cerr << "\nFormat string " << fmt << "\nExpected exception " << what << "\nActual exception " - << e.what() << '\n'; -# endif - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#endif - (void)what; - (void)fmt; - (void)sizeof...(args); +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::format become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in format.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/format.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/format.verify.cpp @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// 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 +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// string format(format-string fmt, const Args&... args); +// template +// wstring format(wformat-string fmt, const Args&... args); + +#include + +#include "test_macros.h" + +// clang-format off + +void f() { + std::format("{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format("{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::format(L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format(L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp @@ -17,10 +17,10 @@ // template // Out format_to(Out out, const locale& loc, -// string_view fmt, const Args&... args); +// format-string fmt, const Args&... args); // template // Out format_to(Out out, const locale& loc, -// wstring_view fmt, const Args&... args); +// wformat-string fmt, const Args&... args); #include #include @@ -60,23 +60,11 @@ } }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::basic_string out; - std::format_to(std::back_inserter(out), std::locale(), fmt, args...); - assert(false); - } catch (const std::format_error& e) { - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::format_to become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in format_to.locale.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.verify.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// 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: no-localization +// UNSUPPORTED: libcpp-has-no-incomplete-format +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// Out format_to(Out out, const locale& loc, +// format-string fmt, const Args&... args); +// template +// Out format_to(Out out, const locale& loc, +// wformat-string fmt, const Args&... args); + +#include +#include + +#include "test_macros.h" + +extern char* out; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +extern wchar_t* wout; +#endif + +// clang-format off + +void f() { + std::format_to(out, std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::format_to(wout, std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp @@ -15,9 +15,9 @@ // // template -// Out format_to(Out out, string_view fmt, const Args&... args); +// Out format_to(Out out, format-string fmt, const Args&... args); // template -// Out format_to(Out out, wstring_view fmt, const Args&... args); +// Out format_to(Out out, wformat-string fmt, const Args&... args); #include #include @@ -57,23 +57,11 @@ } }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::basic_string out; - std::format_to(std::back_inserter(out), fmt, args...); - assert(false); - } catch (const std::format_error& e) { - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::format become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in format.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/format_to.verify.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// 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 +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// + +// Basic test to validate ill-formed code is properly detected. + +// template +// Out format_to(Out out, format-string fmt, const Args&... args); +// template +// Out format_to(Out out, wformat-string fmt, const Args&... args); + +#include + +#include "test_macros.h" + +extern char* out; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +extern wchar_t* wout; +#endif + +// clang-format off + +void f() { + std::format_to(out, "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(out, "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::format_to(wout, L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to(wout, L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp @@ -17,11 +17,11 @@ // template // format_to_n_result format_to_n(Out out, iter_difference_t n, -// const locale& loc, string_view fmt, +// const locale& loc, format-string fmt, // const Args&... args); // template // format_to_n_result format_to_n(Out out, iter_difference_t n, -// const locale& loc, wstring_view fmt, +// const locale& loc, wformat-string fmt, // const Args&... args); #include @@ -98,23 +98,11 @@ } }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::basic_string out; - std::format_to_n(std::back_inserter(out), 0, std::locale(), fmt, args...); - assert(false); - } catch (const std::format_error& e) { - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::format_to_n become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in format_to_n.locale.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.verify.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// 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: no-localization +// UNSUPPORTED: libcpp-has-no-incomplete-format +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// format_to_n_result format_to_n(Out out, iter_difference_t n, +// const locale& loc, format-string fmt, +// const Args&... args); +// template +// format_to_n_result format_to_n(Out out, iter_difference_t n, +// const locale& loc, wformat-string fmt, +// const Args&... args); + +#include +#include + +#include "test_macros.h" + +extern char* out; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +extern wchar_t* wout; +#endif + +// clang-format off + +void f() { + std::format_to_n(out, 42, std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::format_to_n(wout, 42, std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp @@ -16,10 +16,10 @@ // template // format_to_n_result format_to_n(Out out, iter_difference_t n, -// string_view fmt, const Args&... args); +// format-string fmt, const Args&... args); // template // format_to_n_result format_to_n(Out out, iter_difference_t n, -// wstring_view fmt, const Args&... args); +// wformat-string fmt, const Args&... args); #include #include @@ -91,23 +91,11 @@ } }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::basic_string out; - std::format_to_n(std::back_inserter(out), 0, fmt, args...); - assert(false); - } catch (const std::format_error& e) { - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::format_to_n become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in format_to_n.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.verify.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// 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 +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// format_to_n_result format_to_n(Out out, iter_difference_t n, +// format-string fmt, const Args&... args); +// template +// format_to_n_result format_to_n(Out out, iter_difference_t n, +// wformat-string fmt, const Args&... args); + +#include + +#include "test_macros.h" + +extern char* out; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +extern wchar_t* wout; +#endif + +// clang-format off + +void f() { + std::format_to_n(out, 42, "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(out, 42, "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::format_to_n(wout, 42, L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::format_to_n(wout, 42, L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp @@ -17,10 +17,10 @@ // template // size_t formatted_size(const locale& loc, -// string_view fmt, const Args&... args); +// format-string fmt, const Args&... args); // template // size_t formatted_size(const locale& loc, -// wstring_view fmt, const Args&... args); +// wformat-string fmt, const Args&... args); #include #include @@ -36,22 +36,11 @@ assert(size == expected.size()); }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::formatted_size(std::locale(), fmt, args...); - assert(false); - } catch (const std::format_error& e) { - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::formatted_siz3 become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in formatted_size.locale.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.verify.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// 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: no-localization +// UNSUPPORTED: libcpp-has-no-incomplete-format +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// size_t formatted_size(const locale& loc, +// format-string fmt, const Args&... args); +// template +// size_t formatted_size(const locale& loc, +// wformat-string fmt, const Args&... args); + +#include +#include + +#include "test_macros.h" + +// clang-format off + +void f() { + std::formatted_size(std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::formatted_size(std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +} diff --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp @@ -15,9 +15,9 @@ // // template -// size_t formatted_size(string_view fmt, const Args&... args); +// size_t formatted_size(format-string fmt, const Args&... args); // template -// size_t formatted_size(wstring_view fmt, const Args&... args); +// size_t formatted_size(wformat-string fmt, const Args&... args); #include #include @@ -33,22 +33,11 @@ assert(size == expected.size()); }; -auto test_exception = [](std::string_view what, std::basic_string_view fmt, - const Args&... args) { -#ifndef TEST_HAS_NO_EXCEPTIONS - try { - std::formatted_size(fmt, args...); - assert(false); - } catch (const std::format_error& e) { - LIBCPP_ASSERT(e.what() == what); - return; - } - assert(false); -#else - (void)what; - (void)fmt; - (void)sizeof...(args); -#endif +auto test_exception = [](std::string_view, std::basic_string_view, const Args&...) { + // After P2216 most exceptions thrown by std::formatted_siz3 become ill-formed. + // Therefore this tests does nothing. + // A basic ill-formed test is done in formatted_size.verify.cpp + // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. }; int main(int, char**) { diff --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.verify.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.verify.cpp @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// 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 +// TODO FMT Evaluate gcc-11 status +// UNSUPPORTED: gcc-11 + +// Basic test to validate ill-formed code is properly detected. + +// + +// template +// size_t formatted_size(format-string fmt, const Args&... args); +// template +// size_t formatted_size(wformat-string fmt, const Args&... args); + +#include + +#include "test_macros.h" + +// clang-format off + +void f() { + std::formatted_size("{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size("{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::formatted_size(L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} + + std::formatted_size(L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}} + // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}} +#endif +}