Compile-time error on too many arguments provided
Adds a compile time error if the number of arguments provided to the format function is larger than the number of braces in the format string. Only works in automatic argument indexing mode. This check deliberately only works for compile-time format string checking, not at runtime. This is because we don't want existing code to have unexpected runtime errors after upgrades. There are also scenarios imaginable where either the arguments or the format string is generated at runtime, and the ability to have less braces in the format string can actually be a feature. At the same time, compile-time format calls are guaranteed to be constant. In other words, having too many arguments will always mean there's a bug in the code. The new feature works by adding a on_end_of_string() function to formatting handlers. This function is called after the whole format string has been parsed, and needs to be implemented by all parsing handlers.
This commit is contained in:
parent
ccc8f5db02
commit
0aa4721472
@ -82,6 +82,8 @@ template <typename Char> struct part_counter {
|
||||
return begin;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void on_end_of_string() {}
|
||||
|
||||
FMT_CONSTEXPR void on_error(const char*) {}
|
||||
};
|
||||
|
||||
@ -148,6 +150,8 @@ class format_string_compiler : public error_handler {
|
||||
handler_(part);
|
||||
return it;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void on_end_of_string() {}
|
||||
};
|
||||
|
||||
// Compiles a format string and invokes handler(part) for each parsed part.
|
||||
|
||||
@ -489,6 +489,9 @@ class basic_parse_context : private ErrorHandler {
|
||||
|
||||
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
|
||||
|
||||
FMT_CONSTEXPR bool is_auto_arg_indexing() { return next_arg_id_ >= 0; }
|
||||
FMT_CONSTEXPR int num_auto_args() { return next_arg_id_; }
|
||||
|
||||
FMT_CONSTEXPR void on_error(const char* message) {
|
||||
ErrorHandler::on_error(message);
|
||||
}
|
||||
|
||||
@ -2477,8 +2477,10 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
|
||||
// Doing two passes with memchr (one for '{' and another for '}') is up to
|
||||
// 2.5x faster than the naive one-pass implementation on big format strings.
|
||||
const Char* p = begin;
|
||||
if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p))
|
||||
if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p)) {
|
||||
handler.on_end_of_string();
|
||||
return write(begin, end);
|
||||
}
|
||||
write(begin, p);
|
||||
++p;
|
||||
if (p == end) return handler.on_error("invalid format string");
|
||||
@ -2502,6 +2504,7 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
|
||||
}
|
||||
begin = p + 1;
|
||||
}
|
||||
handler.on_end_of_string();
|
||||
}
|
||||
|
||||
template <typename T, typename ParseContext>
|
||||
@ -2551,6 +2554,11 @@ class format_string_checker {
|
||||
return arg_id_ < num_args ? parse_funcs_[arg_id_](context_) : begin;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void on_end_of_string() {
|
||||
if (context_.is_auto_arg_indexing() && context_.num_auto_args() < num_args)
|
||||
context_.on_error("number of arguments in format string is less than number of arguments provided");
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void on_error(const char* message) {
|
||||
context_.on_error(message);
|
||||
}
|
||||
@ -3212,6 +3220,8 @@ struct format_handler : internal::error_handler {
|
||||
return begin;
|
||||
}
|
||||
|
||||
void on_end_of_string() {}
|
||||
|
||||
basic_parse_context<Char> parse_context;
|
||||
Context context;
|
||||
basic_format_arg<Context> arg;
|
||||
|
||||
@ -2377,6 +2377,8 @@ struct test_format_string_handler {
|
||||
return begin;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void on_end_of_string() {}
|
||||
|
||||
FMT_CONSTEXPR void on_error(const char*) { error = true; }
|
||||
|
||||
bool error = false;
|
||||
@ -2496,6 +2498,8 @@ TEST(FormatTest, FormatStringErrors) {
|
||||
EXPECT_ERROR("{}{1}",
|
||||
"cannot switch from automatic to manual argument indexing", int,
|
||||
int);
|
||||
EXPECT_ERROR("", "number of arguments in format string is less than number of arguments provided", int);
|
||||
EXPECT_ERROR("{}", "number of arguments in format string is less than number of arguments provided", int, int);
|
||||
}
|
||||
|
||||
TEST(FormatTest, VFormatTo) {
|
||||
|
||||
@ -212,6 +212,8 @@ struct scan_handler : error_handler {
|
||||
arg_.custom.scan(arg_.custom.value, parse_ctx_, scan_ctx_);
|
||||
return parse_ctx_.begin();
|
||||
}
|
||||
|
||||
void on_end_of_string() {}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user