diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 933668c4..3036b6a6 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -337,8 +337,8 @@ template constexpr parse_specs_result parse_specs(basic_string_view str, size_t pos, int next_arg_id) { str.remove_prefix(pos); - auto ctx = compile_parse_context(str, max_value(), nullptr, {}, - next_arg_id); + auto ctx = + compile_parse_context(str, max_value(), nullptr, next_arg_id); auto f = formatter(); auto end = f.parse(ctx); return {f, pos + fmt::detail::to_unsigned(end - str.data()), diff --git a/include/fmt/core.h b/include/fmt/core.h index 96e13151..f447814d 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -659,8 +659,7 @@ template using char_t = typename detail::char_t_impl::type; You can use the ``format_parse_context`` type alias for ``char`` instead. \endrst */ -template -class basic_format_parse_context : private ErrorHandler { +template class basic_format_parse_context { private: basic_string_view format_str_; int next_arg_id_; @@ -672,9 +671,8 @@ class basic_format_parse_context : private ErrorHandler { using iterator = typename basic_string_view::iterator; explicit constexpr basic_format_parse_context( - basic_string_view format_str, ErrorHandler eh = {}, - int next_arg_id = 0) - : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} + basic_string_view format_str, int next_arg_id = 0) + : format_str_(format_str), next_arg_id_(next_arg_id) {} /** Returns an iterator to the beginning of the format string range being @@ -700,7 +698,8 @@ class basic_format_parse_context : private ErrorHandler { */ FMT_CONSTEXPR auto next_arg_id() -> int { if (next_arg_id_ < 0) { - on_error("cannot switch from manual to automatic argument indexing"); + detail::throw_format_error( + "cannot switch from manual to automatic argument indexing"); return 0; } int id = next_arg_id_++; @@ -714,7 +713,8 @@ class basic_format_parse_context : private ErrorHandler { */ FMT_CONSTEXPR void check_arg_id(int id) { if (next_arg_id_ > 0) { - on_error("cannot switch from automatic to manual argument indexing"); + detail::throw_format_error( + "cannot switch from automatic to manual argument indexing"); return; } next_arg_id_ = -1; @@ -722,44 +722,37 @@ class basic_format_parse_context : private ErrorHandler { } FMT_CONSTEXPR void check_arg_id(basic_string_view) {} FMT_CONSTEXPR void check_dynamic_spec(int arg_id); - - FMT_CONSTEXPR void on_error(const char* message) { - ErrorHandler::on_error(message); - } - - constexpr auto error_handler() const -> ErrorHandler { return *this; } }; using format_parse_context = basic_format_parse_context; FMT_BEGIN_DETAIL_NAMESPACE // A parse context with extra data used only in compile-time checks. -template -class compile_parse_context - : public basic_format_parse_context { +template +class compile_parse_context : public basic_format_parse_context { private: int num_args_; const type* types_; - using base = basic_format_parse_context; + using base = basic_format_parse_context; public: explicit FMT_CONSTEXPR compile_parse_context( basic_string_view format_str, int num_args, const type* types, - ErrorHandler eh = {}, int next_arg_id = 0) - : base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {} + int next_arg_id = 0) + : base(format_str, next_arg_id), num_args_(num_args), types_(types) {} constexpr auto num_args() const -> int { return num_args_; } constexpr auto arg_type(int id) const -> type { return types_[id]; } FMT_CONSTEXPR auto next_arg_id() -> int { int id = base::next_arg_id(); - if (id >= num_args_) this->on_error("argument not found"); + if (id >= num_args_) throw_format_error("argument not found"); return id; } FMT_CONSTEXPR void check_arg_id(int id) { base::check_arg_id(id); - if (id >= num_args_) this->on_error("argument not found"); + if (id >= num_args_) throw_format_error("argument not found"); } using base::check_arg_id; @@ -767,31 +760,30 @@ class compile_parse_context detail::ignore_unused(arg_id); #if !defined(__LCC__) if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) - this->on_error("width/precision is not integer"); + throw_format_error("width/precision is not integer"); #endif } }; FMT_END_DETAIL_NAMESPACE -template -FMT_CONSTEXPR void -basic_format_parse_context::do_check_arg_id(int id) { +template +FMT_CONSTEXPR void basic_format_parse_context::do_check_arg_id(int id) { // Argument id is only checked at compile-time during parsing because // formatting has its own validation. if (detail::is_constant_evaluated() && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { - using context = detail::compile_parse_context; + using context = detail::compile_parse_context; if (id >= static_cast(this)->num_args()) - on_error("argument not found"); + detail::throw_format_error("argument not found"); } } -template -FMT_CONSTEXPR void -basic_format_parse_context::check_dynamic_spec(int arg_id) { +template +FMT_CONSTEXPR void basic_format_parse_context::check_dynamic_spec( + int arg_id) { if (detail::is_constant_evaluated() && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { - using context = detail::compile_parse_context; + using context = detail::compile_parse_context; static_cast(this)->check_dynamic_spec(arg_id); } } @@ -2290,7 +2282,7 @@ class dynamic_specs_handler } FMT_CONSTEXPR void on_error(const char* message) { - context_.on_error(message); + throw_format_error(message); } private: @@ -2959,13 +2951,13 @@ FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { template class format_string_checker { private: - // In the future basic_format_parse_context will replace compile_parse_context - // here and will use is_constant_evaluated and downcasting to access the data - // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. - using parse_context_type = compile_parse_context; + using parse_context_type = compile_parse_context; static constexpr int num_args = sizeof...(Args); // Format specifier parsing function. + // In the future basic_format_parse_context will replace compile_parse_context + // here and will use is_constant_evaluated and downcasting to access the data + // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. using parse_func = const Char* (*)(parse_context_type&); parse_context_type context_; @@ -2974,8 +2966,8 @@ class format_string_checker { public: explicit FMT_CONSTEXPR format_string_checker( - basic_string_view format_str, ErrorHandler eh) - : context_(format_str, num_args, types_, eh), + basic_string_view format_str) + : context_(format_str, num_args, types_), parse_funcs_{&parse_format_specs...}, types_{ mapped_type_constant...>; FMT_CONSTEXPR bool invalid_format = - (parse_format_string(s, checker(s, {})), true); + (parse_format_string(s, checker(s)), true); ignore_unused(invalid_format); } @@ -3067,7 +3059,7 @@ struct formatter(handler_type(specs_, ctx), type); auto it = detail::parse_format_specs(begin, end, checker); - auto eh = ctx.error_handler(); + auto eh = detail::error_handler(); switch (type) { case detail::type::none_type: FMT_ASSERT(false, "invalid argument type"); @@ -3181,7 +3173,7 @@ template class basic_format_string { detail::count_statically_named_args()) { using checker = detail::format_string_checker...>; - detail::parse_format_string(str_, checker(s, {})); + detail::parse_format_string(str_, checker(s)); } #else detail::check_format_string(s); diff --git a/include/fmt/format.h b/include/fmt/format.h index ab1db08a..f3219b75 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3992,7 +3992,7 @@ template <> struct formatter { detail::specs_checker handler(handler_type(specs_, ctx), detail::type::string_type); auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); - detail::check_string_type_spec(specs_.type, ctx.error_handler()); + detail::check_string_type_spec(specs_.type, detail::error_handler()); return it; } @@ -4035,7 +4035,7 @@ template struct formatter> : formatter { detail::specs_checker handler(handler_type(specs_, ctx), detail::type::int_type); auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); - detail::check_string_type_spec(specs_.type, ctx.error_handler()); + detail::check_string_type_spec(specs_.type, detail::error_handler()); return it; } diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 6c587382..3b4b80a8 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -402,7 +402,7 @@ void vprintf(buffer& buf, basic_string_view format, // Parse argument index, flags and width. int arg_index = parse_header(it, end, specs, get_arg); - if (arg_index == 0) parse_ctx.on_error("argument not found"); + if (arg_index == 0) throw_format_error("argument not found"); // Parse precision. if (it != end && *it == '.') { @@ -504,7 +504,7 @@ void vprintf(buffer& buf, basic_string_view format, } specs.type = parse_presentation_type(type); if (specs.type == presentation_type::none) - parse_ctx.on_error("invalid type specifier"); + throw_format_error("invalid type specifier"); start = it; diff --git a/test/xchar-test.cc b/test/xchar-test.cc index f4abbda8..67b73ba9 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -469,7 +469,7 @@ template struct formatter, charT> { detail::specs_checker handler(handler_type(specs_, ctx), detail::type::string_type); auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); - detail::parse_float_type_spec(specs_, ctx.error_handler()); + detail::parse_float_type_spec(specs_, detail::error_handler()); return it; }