mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-16 14:42:25 +00:00
Implement compile-time checks for dynamic width/precision type
This commit is contained in:
parent
bc5c7c50fd
commit
48e0a59222
@ -710,8 +710,8 @@ class basic_format_parse_context : private ErrorHandler {
|
|||||||
next_arg_id_ = -1;
|
next_arg_id_ = -1;
|
||||||
do_check_arg_id(id);
|
do_check_arg_id(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
|
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
|
||||||
|
FMT_CONSTEXPR void check_dynamic_spec(int arg_id);
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
ErrorHandler::on_error(message);
|
ErrorHandler::on_error(message);
|
||||||
@ -738,7 +738,8 @@ class compile_parse_context
|
|||||||
ErrorHandler eh = {}, int next_arg_id = 0)
|
ErrorHandler eh = {}, int next_arg_id = 0)
|
||||||
: base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {}
|
: base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {}
|
||||||
|
|
||||||
constexpr int num_args() const { return num_args_; }
|
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 {
|
FMT_CONSTEXPR auto next_arg_id() -> int {
|
||||||
int id = base::next_arg_id();
|
int id = base::next_arg_id();
|
||||||
@ -751,6 +752,11 @@ class compile_parse_context
|
|||||||
if (id >= num_args_) this->on_error("argument not found");
|
if (id >= num_args_) this->on_error("argument not found");
|
||||||
}
|
}
|
||||||
using base::check_arg_id;
|
using base::check_arg_id;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
|
||||||
|
if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
|
||||||
|
this->on_error("width/precision is not integer");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
FMT_END_DETAIL_NAMESPACE
|
FMT_END_DETAIL_NAMESPACE
|
||||||
|
|
||||||
@ -766,6 +772,15 @@ basic_format_parse_context<Char, ErrorHandler>::do_check_arg_id(int id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename ErrorHandler>
|
||||||
|
FMT_CONSTEXPR void
|
||||||
|
basic_format_parse_context<Char, ErrorHandler>::check_dynamic_spec(int arg_id) {
|
||||||
|
if (detail::is_constant_evaluated()) {
|
||||||
|
using context = detail::compile_parse_context<Char, ErrorHandler>;
|
||||||
|
static_cast<context*>(this)->check_dynamic_spec(arg_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Context> class basic_format_arg;
|
template <typename Context> class basic_format_arg;
|
||||||
template <typename Context> class basic_format_args;
|
template <typename Context> class basic_format_args;
|
||||||
template <typename Context> class dynamic_format_arg_store;
|
template <typename Context> class dynamic_format_arg_store;
|
||||||
@ -2243,11 +2258,14 @@ class dynamic_specs_handler
|
|||||||
|
|
||||||
FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type {
|
FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type {
|
||||||
context_.check_arg_id(arg_id);
|
context_.check_arg_id(arg_id);
|
||||||
|
context_.check_dynamic_spec(arg_id);
|
||||||
return arg_ref_type(arg_id);
|
return arg_ref_type(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
|
FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
|
||||||
return arg_ref_type(context_.next_arg_id());
|
int arg_id = context_.next_arg_id();
|
||||||
|
context_.check_dynamic_spec(arg_id);
|
||||||
|
return arg_ref_type(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
|
FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
|
||||||
|
@ -584,6 +584,7 @@ struct test_parse_context {
|
|||||||
|
|
||||||
constexpr int next_arg_id() { return 11; }
|
constexpr int next_arg_id() { return 11; }
|
||||||
template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {}
|
template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {}
|
||||||
|
FMT_CONSTEXPR void check_dynamic_spec(int) {}
|
||||||
|
|
||||||
constexpr const char* begin() { return nullptr; }
|
constexpr const char* begin() { return nullptr; }
|
||||||
constexpr const char* end() { return nullptr; }
|
constexpr const char* end() { return nullptr; }
|
||||||
|
@ -2177,6 +2177,7 @@ TEST(format_test, format_string_errors) {
|
|||||||
EXPECT_ERROR("{: }", "format specifier requires signed argument", unsigned);
|
EXPECT_ERROR("{: }", "format specifier requires signed argument", unsigned);
|
||||||
EXPECT_ERROR("{:{}}", "argument not found", int);
|
EXPECT_ERROR("{:{}}", "argument not found", int);
|
||||||
EXPECT_ERROR("{:.{}}", "argument not found", double);
|
EXPECT_ERROR("{:.{}}", "argument not found", double);
|
||||||
|
EXPECT_ERROR("{:{}}", "width/precision is not integer", int, double);
|
||||||
EXPECT_ERROR("{:.2}", "precision not allowed for this argument type", int);
|
EXPECT_ERROR("{:.2}", "precision not allowed for this argument type", int);
|
||||||
EXPECT_ERROR("{:s}", "invalid type specifier", int);
|
EXPECT_ERROR("{:s}", "invalid type specifier", int);
|
||||||
EXPECT_ERROR("{:s}", "invalid type specifier", char);
|
EXPECT_ERROR("{:s}", "invalid type specifier", char);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user