From a03842b0d5de370c3950cdd51b5ec697b8bce600 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 5 Nov 2017 13:18:42 -0800 Subject: [PATCH] More compile-time checks --- include/fmt/format.h | 32 ++++++++++++++++++-------------- test/format-test.cc | 10 ++++++---- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index da7e0e45..25bd6950 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3812,33 +3812,37 @@ struct udl_format_handler { constexpr void on_text(const Char *, const Char *) {} - constexpr void on_arg_id() { ++arg_index_; } - - template - constexpr void on_arg_id(T) {} + constexpr void on_arg_id() { + ++arg_index_; + check_arg_index(); + } + constexpr void on_arg_id(unsigned index) { + arg_index_ = index; + check_arg_index(); + } + constexpr void on_arg_id(basic_string_view) {} constexpr void on_replacement_field(const Char *) {} constexpr const Char *on_format_specs(const Char *s) { - if (arg_index_ < 0 || arg_index_ >= sizeof...(Args)) { - on_error("argument index out of range"); - return s; - } parse_context ctx(basic_string_view(s, end_ - s)); return parse_funcs_[arg_index_](ctx); } - constexpr void on_error(const char *) { error_ = true; } - - constexpr bool is_valid() const { return !error_; } + // This function is intentionally not constexpr to give a compile-time error. + void on_error(const char *); private: + constexpr void check_arg_index() { + if (arg_index_ < 0 || arg_index_ >= sizeof...(Args)) + on_error("argument index out of range"); + } + // Format specifier parsing function. using parse_func = const Char *(*)(parse_context &); const Char *end_; int arg_index_ = -1; - bool error_ = false; parse_func parse_funcs_[sizeof...(Args)] = { &parse_format_specs... }; @@ -3850,7 +3854,7 @@ class udl_formatter { template std::basic_string operator()(const Args &... args) const { constexpr Char s[] = {CHARS..., '\0'}; - static_assert(check_format(s), "error parsing format string"); + constexpr bool invalid_format = check_format(s); return format(s, args...); } @@ -3859,7 +3863,7 @@ class udl_formatter { static constexpr bool check_format(const Char *s) { udl_format_handler handler(s + sizeof...(CHARS)); internal::parse_format_string(s, handler); - return handler.is_valid(); + return true; } }; # else diff --git a/test/format-test.cc b/test/format-test.cc index 08871e86..a3e64a69 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1234,8 +1234,11 @@ namespace fmt { template <> struct formatter { template - auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { - return ctx.begin(); + constexpr auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + if (*it == 'd') + ++it; + return it; } void format(buffer &buf, const Date &d, context &) { @@ -1813,8 +1816,7 @@ TEST(FormatTest, ConstexprParseFormatString) { static_assert(parse_string("{:}"), ""); } -#if FMT_UDL_TEMPLATE TEST(FormatTest, UdlTemplate) { EXPECT_EQ("foo", "foo"_format()); + EXPECT_EQ(" 42", "{0:10}"_format(42)); } -#endif