diff --git a/include/fmt/format.h b/include/fmt/format.h index a26aeb04..f0a39ad2 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1740,18 +1740,23 @@ constexpr void handle_integral_type_spec(char c, Handler &&handler) { } } -struct int_type_checker { +template +class int_type_checker { + public: + constexpr int_type_checker(ErrorHandler &eh) : eh_(eh) {} + constexpr void on_dec() {} constexpr void on_hex() {} constexpr void on_bin() {} constexpr void on_oct() {} constexpr void on_num() {} - template constexpr void on_error() { - error_handler eh; - eh.on_error("invalid type specifier"); + eh_.on_error("invalid type specifier"); } + + private: + ErrorHandler &eh_; }; template @@ -2218,10 +2223,8 @@ class specs_checker : public Handler { } constexpr void end_precision() { - if (is_integral(arg_type_) || arg_type_ == POINTER) { - report_error("precision not allowed in {} format specifier", - arg_type_ == POINTER ? "pointer" : "integer"); - } + if (is_integral(arg_type_) || arg_type_ == POINTER) + this->on_error("precision not allowed for this argument type"); } private: @@ -2642,7 +2645,8 @@ class format_string_checker : public ErrorHandler { constexpr static size_t NUM_ARGS = sizeof...(Args); constexpr void check_arg_index() { - if (arg_index_ < 0 || arg_index_ >= NUM_ARGS) + unsigned unsigned_index = arg_index_; + if (arg_index_ < 0 || unsigned_index >= NUM_ARGS) this->on_error("argument index out of range"); } @@ -3189,16 +3193,16 @@ typename basic_writer::pointer_type template template void basic_writer::write_int(T value, const Spec& spec) { + using unsigned_type = typename internal::int_traits::main_type; struct spec_handler { basic_writer &writer; const Spec& spec; unsigned prefix_size = 0; - typedef typename internal::int_traits::main_type UnsignedType; - UnsignedType abs_value; + unsigned_type abs_value; char prefix[4] = ""; spec_handler(basic_writer &w, T value, const Spec& s) - : writer(w), spec(s), abs_value(static_cast(value)) { + : writer(w), spec(s), abs_value(static_cast(value)) { if (internal::is_negative(value)) { prefix[0] = '-'; ++prefix_size; @@ -3217,7 +3221,7 @@ void basic_writer::write_int(T value, const Spec& spec) { } void on_hex() { - UnsignedType n = abs_value; + unsigned_type n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); @@ -3237,7 +3241,7 @@ void basic_writer::write_int(T value, const Spec& spec) { } void on_bin() { - UnsignedType n = abs_value; + unsigned_type n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); @@ -3255,7 +3259,7 @@ void basic_writer::write_int(T value, const Spec& spec) { } void on_oct() { - UnsignedType n = abs_value; + unsigned_type n = abs_value; if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; unsigned num_digits = 0; @@ -3764,8 +3768,10 @@ struct formatter< internal::specs_checker handler(handler_type(specs_, ctx), internal::get_type()); it = parse_format_specs(it, handler); - if (std::is_integral::value) - handle_integral_type_spec(specs_.type(), internal::int_type_checker()); + if (std::is_integral::value) { + handle_integral_type_spec( + specs_.type(), internal::int_type_checker(ctx)); + } return pointer_from(it); } @@ -3951,6 +3957,7 @@ class udl_formatter { constexpr bool invalid_format = check_format_string( basic_string_view(s, sizeof...(CHARS))); + (void)invalid_format; return format(s, args...); } }; diff --git a/test/format-test.cc b/test/format-test.cc index e6131430..229a846c 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -847,40 +847,40 @@ TEST(FormatterTest, Precision) { format_error, "missing precision specifier"); EXPECT_THROW_MSG(format("{0:.2", 0), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2}", 42), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2}", 42u), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42u), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2}", 42l), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42l), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2}", 42ul), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42ul), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2}", 42ll), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42ll), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2}", 42ull), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42ull), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:3.0}", 'x'), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_EQ("1.2", format("{0:.2}", 1.2345)); EXPECT_EQ("1.2", format("{0:.2}", 1.2345l)); EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast(0xcafe)), - format_error, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", reinterpret_cast(0xcafe)), - format_error, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_EQ("st", format("{0:.2}", "str")); } @@ -905,7 +905,7 @@ TEST(FormatterTest, RuntimePrecision) { EXPECT_THROW_MSG(format("{0:.{?}}", 0), format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:.{1}", 0, 0), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}}", 0), format_error, "argument index out of range"); @@ -932,38 +932,38 @@ TEST(FormatterTest, RuntimePrecision) { format_error, "precision is not integer"); EXPECT_THROW_MSG(format("{0:.{1}}", 42, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}}", 42u, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42u, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}}", 42l, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42l, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}}", 42ul, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42ul, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}}", 42ll, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42ll, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}}", 42ull, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42ull, 2), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:3.{1}}", 'x', 0), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_EQ("1.2", format("{0:.{1}}", 1.2345, 2)); EXPECT_EQ("1.2", format("{1:.{0}}", 2, 1.2345l)); EXPECT_THROW_MSG(format("{0:.{1}}", reinterpret_cast(0xcafe), 2), - format_error, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.{1}f}", reinterpret_cast(0xcafe), 2), - format_error, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed for this argument type"); EXPECT_EQ("st", format("{0:.{1}}", "str", 2)); } @@ -1578,7 +1578,7 @@ TEST(FormatTest, DynamicFormatter) { EXPECT_THROW_MSG(format("{:0}", str), format_error, "format specifier '=' requires numeric argument"); EXPECT_THROW_MSG(format("{:.2}", num), - format_error, "precision not allowed in integer format specifier"); + format_error, "precision not allowed for this argument type"); } struct test_arg_id_handler { @@ -1876,4 +1876,10 @@ TEST(FormatTest, FormatStringErrors) { EXPECT_ERROR("{0x}", "invalid format string"); EXPECT_ERROR("{-}", "invalid format string"); EXPECT_ERROR("{1}", "argument index out of range", int); + EXPECT_ERROR("{:10000000000}", "number is too big", int); + EXPECT_ERROR("{:{0x}}", "invalid format string", int); + EXPECT_ERROR("{:{-}}", "invalid format string", int); + EXPECT_ERROR("{:.10000000000}", "number is too big", int); + EXPECT_ERROR("{:.{0x}}", "invalid format string", int); + EXPECT_ERROR("{:.{-}}", "invalid format string", int); }