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 @@ -221,7 +221,7 @@ while (state.KeepRunningBatch(1000)) for (F value : data) - benchmark::DoNotOptimize(std::format_to(output.begin(), fmt, value)); + benchmark::DoNotOptimize(std::vformat_to(output.begin(), fmt, std::make_format_args(value))); } std::string name() const { 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","|In progress|","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; @@ -202,8 +213,181 @@ namespace __format { +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) + : __args_(__args), __handles_(__handles) {} + + // 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 { + // Accessing array out of bounds is UB thus an error. + return __args_[__id]; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const { + // Accessing array out of bounds is UB thus an error. + 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_; +}; + +template +consteval void __get_handle(__compile_time_handle<_CharT>* __handle) { + using _Context = __format::__compile_time_basic_format_context<_CharT>; + if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) + __handle->template __enable<_Tp>(); + + if constexpr (sizeof...(_Args)) + __format::__get_handle<_CharT, _Args...>(++__handle); +} + +template +consteval array<__compile_time_handle<_CharT>, sizeof...(_Args)> __get_handle() { + if constexpr (sizeof...(_Args) == 0) + return array<__compile_time_handle<_CharT>,0>{}; + else { + array<__compile_time_handle<_CharT>, sizeof...(_Args)> __result; + __format::__get_handle<_CharT, _Args...>(__result.data()); + return __result; + } +} + +_LIBCPP_HIDE_FROM_ABI +constexpr void __compile_time_validate_integral(__arg_t __type) { + switch (__type) { + case __arg_t::__int: + case __arg_t::__long_long: +# ifndef _LIBCPP_HAS_NO_INT128 + case __arg_t::__i128: +# endif + case __arg_t::__unsigned: + case __arg_t::__unsigned_long_long: +# ifndef _LIBCPP_HAS_NO_INT128 + case __arg_t::__u128: +# endif + return; + + default: + __throw_format_error("Argument isn't an integral"); + } +} + +// _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 = @@ -223,19 +407,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('}')) @@ -245,7 +436,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); @@ -288,8 +479,48 @@ return __out_it; } +template +consteval array<__arg_t, sizeof...(_Args)> __get_types() { + if constexpr (sizeof...(_Args) != 0) { + array<__arg_t, sizeof...(_Args)> __result; + __arg_t* __types = __result.data(); + ([&] { *__types++ = __determine_arg_t<_Context, _Args>(); }(), ...); + return __result; + } else + return {}; +} + } // 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()}); + } + +private: + using _Context = __format::__compile_time_basic_format_context<_CharT>; + + static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{ + __format::__get_types<_Context, remove_cvref_t<_Args>...>()}; + + static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{ + __format::__get_handle<_CharT, remove_cvref_t<_Args>...>()}; +}; +/* +template +using __format_string = __basic_format_string...>; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +using __wformat_string = __basic_format_string...>; +#endif +*/ template requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to( @@ -325,16 +556,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, __basic_format_string...> __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, __basic_format_string...> __fmt, const _Args&... __args) { + return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -357,24 +588,24 @@ 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...)); +format(__basic_format_string...> __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(__basic_format_string...> __fmt, const _Args&... __args) { + return _VSTD::vformat(__fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif template _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, string_view __fmt, +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, __basic_format_string...> __fmt, const _Args&... __args) { // TODO FMT Improve PoC: using std::string is inefficient. - string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)); + string __str = _VSTD::vformat(__fmt.__str_, _VSTD::make_format_args(__args...)); iter_difference_t<_OutIt> __s = __str.size(); iter_difference_t<_OutIt> __m = _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); @@ -385,10 +616,10 @@ #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template _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, wstring_view __fmt, +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, __basic_format_string...> __fmt, const _Args&... __args) { // TODO FMT Improve PoC: using std::string is inefficient. - wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)); + wstring __str = _VSTD::vformat(__fmt.__str_, _VSTD::make_wformat_args(__args...)); iter_difference_t<_OutIt> __s = __str.size(); iter_difference_t<_OutIt> __m = _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); @@ -406,16 +637,16 @@ } template -_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(string_view __fmt, +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(__basic_format_string...> __fmt, const _Args&... __args) { - return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_format_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, +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(__basic_format_string...> __fmt, const _Args&... __args) { - return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_wformat_args(__args...)}); + return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)}); } #endif @@ -459,16 +690,16 @@ 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, + _OutIt __out_it, locale __loc, __basic_format_string...> __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, + _OutIt __out_it, locale __loc, __basic_format_string...> __fmt, const _Args&... __args) { + return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -493,16 +724,16 @@ 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, +format(locale __loc, __basic_format_string...> __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, __basic_format_string...> __fmt, const _Args&... __args) { + return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_, _VSTD::make_wformat_args(__args...)); } #endif @@ -510,9 +741,9 @@ template _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, locale __loc, - string_view __fmt, const _Args&... __args) { + __basic_format_string...> __fmt, const _Args&... __args) { // TODO FMT Improve PoC: using std::string is inefficient. - string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt, + string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_, _VSTD::make_format_args(__args...)); iter_difference_t<_OutIt> __s = __str.size(); iter_difference_t<_OutIt> __m = @@ -525,9 +756,9 @@ template _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, locale __loc, - wstring_view __fmt, const _Args&... __args) { + __basic_format_string...> __fmt, const _Args&... __args) { // TODO FMT Improve PoC: using std::string is inefficient. - wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt, + wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_, _VSTD::make_wformat_args(__args...)); iter_difference_t<_OutIt> __s = __str.size(); iter_difference_t<_OutIt> __m = @@ -548,17 +779,17 @@ template _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc, - string_view __fmt, + __basic_format_string...> __fmt, const _Args&... __args) { - return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_format_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, + __basic_format_string...> __fmt, const _Args&... __args) { - return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_wformat_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.localeverify.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: libcpp-has-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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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: libcpp-has-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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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: libcpp-has-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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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: libcpp-has-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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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@*:* {{read of dereferenced null pointer is not allowed 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 +}