From bcc20b29df13c718f6e02fbfeec96e32e66fd5f9 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 15 Nov 2020 09:03:20 -0800 Subject: [PATCH] Implement compile-time checks by default --- .github/workflows/linux.yml | 4 + include/fmt/chrono.h | 59 ++++---- include/fmt/core.h | 8 +- include/fmt/format-inl.h | 3 +- include/fmt/format.h | 28 +++- include/fmt/ranges.h | 14 +- test/CMakeLists.txt | 2 +- test/chrono-test.cc | 50 ++++--- test/core-test.cc | 13 +- test/format-test.cc | 286 ++++++++++++++++++------------------ test/locale-test.cc | 2 +- test/ostream-test.cc | 12 +- 12 files changed, 258 insertions(+), 223 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 49a6ae0b..d241678a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -17,6 +17,9 @@ jobs: std: 14 - cxx: g++-10 std: 17 + - cxx: g++-10 + std: 20 + cxxflags: -DFMT_COMPILE_TIME_CHECKS=1 - cxx: clang++-9 std: 11 - cxx: clang++-9 @@ -36,6 +39,7 @@ jobs: working-directory: ${{runner.workspace}}/build env: CXX: ${{matrix.cxx}} + CXXFLAGS: ${{matrix.cxxflags}} run: | cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \ diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index a05bfa14..d68d8c9a 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -404,20 +404,20 @@ struct formatter, Char> }; template struct formatter { - template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); if (it != ctx.end() && *it == ':') ++it; auto end = it; while (end != ctx.end() && *end != '}') ++end; - tm_format.reserve(detail::to_unsigned(end - it + 1)); - tm_format.append(it, end); - tm_format.push_back('\0'); + specs = {it, detail::to_unsigned(end - it)}; return end; } template auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) { + basic_memory_buffer tm_format; + tm_format.append(specs.begin(), specs.end()); + tm_format.push_back('\0'); basic_memory_buffer buf; size_t start = buf.size(); for (;;) { @@ -440,7 +440,7 @@ template struct formatter { return std::copy(buf.begin(), buf.end(), ctx.out()); } - basic_memory_buffer tm_format; + basic_string_view specs; }; namespace detail { @@ -638,28 +638,29 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, struct chrono_format_checker { FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); } - template void on_text(const Char*, const Char*) {} + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} FMT_NORETURN void on_abbr_weekday() { report_no_date(); } FMT_NORETURN void on_full_weekday() { report_no_date(); } FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); } FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); } FMT_NORETURN void on_abbr_month() { report_no_date(); } FMT_NORETURN void on_full_month() { report_no_date(); } - void on_24_hour(numeric_system) {} - void on_12_hour(numeric_system) {} - void on_minute(numeric_system) {} - void on_second(numeric_system) {} + FMT_CONSTEXPR void on_24_hour(numeric_system) {} + FMT_CONSTEXPR void on_12_hour(numeric_system) {} + FMT_CONSTEXPR void on_minute(numeric_system) {} + FMT_CONSTEXPR void on_second(numeric_system) {} FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); } FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); } FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); } FMT_NORETURN void on_us_date() { report_no_date(); } FMT_NORETURN void on_iso_date() { report_no_date(); } - void on_12_hour_time() {} - void on_24_hour_time() {} - void on_iso_time() {} - void on_am_pm() {} - void on_duration_value() {} - void on_duration_unit() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_duration_value() {} + FMT_CONSTEXPR void on_duration_unit() {} FMT_NORETURN void on_utc_offset() { report_no_date(); } FMT_NORETURN void on_tz_name() { report_no_date(); } }; @@ -1033,11 +1034,11 @@ template struct formatter, Char> { private: basic_format_specs specs; - int precision; + int precision = -1; using arg_ref_type = detail::arg_ref; arg_ref_type width_ref; arg_ref_type precision_ref; - mutable basic_string_view format_str; + basic_string_view format_str; using duration = std::chrono::duration; struct spec_handler { @@ -1060,17 +1061,21 @@ struct formatter, Char> { } void on_error(const char* msg) { FMT_THROW(format_error(msg)); } - void on_fill(basic_string_view fill) { f.specs.fill = fill; } - void on_align(align_t align) { f.specs.align = align; } - void on_width(int width) { f.specs.width = width; } - void on_precision(int _precision) { f.precision = _precision; } - void end_precision() {} + FMT_CONSTEXPR void on_fill(basic_string_view fill) { + f.specs.fill = fill; + } + FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; } + FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; } + FMT_CONSTEXPR void on_precision(int _precision) { + f.precision = _precision; + } + FMT_CONSTEXPR void end_precision() {} - template void on_dynamic_width(Id arg_id) { + template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { f.width_ref = make_arg_ref(arg_id); } - template void on_dynamic_precision(Id arg_id) { + template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { f.precision_ref = make_arg_ref(arg_id); } }; @@ -1100,8 +1105,6 @@ struct formatter, Char> { } public: - formatter() : precision(-1) {} - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) -> decltype(ctx.begin()) { auto range = do_parse(ctx); diff --git a/include/fmt/core.h b/include/fmt/core.h index 936290c4..02bd3129 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -249,6 +249,10 @@ # pragma execution_character_set("utf-8") #endif +#ifndef FMT_COMPILE_TIME_CHECKS +# define FMT_COMPILE_TIME_CHECKS 0 +#endif + FMT_BEGIN_NAMESPACE // Implementations of enable_if_t and other metafunctions for older systems. @@ -1864,7 +1868,9 @@ FMT_INLINE std::basic_string vformat( */ // Pass char_t as a default template parameter instead of using // std::basic_string> to reduce the symbol size. -template > +template , + FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS || + !std::is_same::value)> FMT_INLINE std::basic_string format(const S& format_str, Args&&... args) { const auto& vargs = fmt::make_args_checked(format_str, args...); return detail::vformat(to_string_view(format_str), vargs); diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index cf483acb..1e38951e 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -2652,7 +2652,8 @@ struct stringifier { } // namespace detail template <> struct formatter { - format_parse_context::iterator parse(format_parse_context& ctx) { + FMT_CONSTEXPR format_parse_context::iterator parse( + format_parse_context& ctx) { return ctx.begin(); } diff --git a/include/fmt/format.h b/include/fmt/format.h index eddde267..b5ecdaeb 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3065,7 +3065,7 @@ FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( using mapped_type = conditional_t::value != type::custom_type, - decltype(arg_mapper().map(std::declval())), T>; + decltype(arg_mapper().map(std::declval())), T>; auto f = conditional_t::value, formatter, detail::fallback_formatter>(); @@ -3561,7 +3561,7 @@ template class dynamic_formatter { public: template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { format_str_ = ctx.begin(); // Checks are deferred to formatting time when the argument type is known. detail::dynamic_specs_handler handler(specs_, ctx); @@ -3864,6 +3864,30 @@ make_format_to_n_args(const Args&... args) { return format_arg_store, Args...>(args...); } +#if FMT_COMPILE_TIME_CHECKS +template struct format_string { + string_view str; + + template consteval format_string(const char (&s)[N]) : str(s) { + if constexpr (detail::count_named_args() == 0) { + using checker = detail::format_string_checker...>; + detail::parse_format_string(string_view(s, N), checker(s, {})); + } + } + + template )> + format_string(const T& s) : str(s) {} +}; + +template +FMT_INLINE std::string format( + format_string...> format_str, Args&&... args) { + return detail::vformat(format_str.str, make_format_args(args...)); +} +#endif + template ::value), int>> std::basic_string detail::vformat( basic_string_view format_str, diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 650d38c9..63cad9ab 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -36,20 +36,18 @@ struct formatting_range : formatting_base { static FMT_CONSTEXPR_DECL const size_t range_length_limit = FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the // range. - Char prefix; - Char delimiter; - Char postfix; - formatting_range() : prefix('{'), delimiter(','), postfix('}') {} + Char prefix = '{'; + Char delimiter = ','; + Char postfix = '}'; static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; }; template struct formatting_tuple : formatting_base { - Char prefix; - Char delimiter; - Char postfix; - formatting_tuple() : prefix('('), delimiter(','), postfix(')') {} + Char prefix = '('; + Char delimiter = ','; + Char postfix = ')'; static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7ae5659d..45721a6d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -148,7 +148,7 @@ endif () message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}") -if (FMT_PEDANTIC) +if (FMT_PEDANTIC AND CXX_STANDARD LESS 20) # MSVC fails to compile GMock when C++17 is enabled. if (FMT_HAS_VARIANT AND NOT MSVC) add_fmt_test(std-format-test) diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 56507449..6c4ff6da 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -96,12 +96,14 @@ TEST(TimeTest, GMTime) { } TEST(TimeTest, TimePoint) { - std::chrono::system_clock::time_point point = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point point = + std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(point); std::tm tm = *std::localtime(&t); char strftime_output[256]; - std::strftime(strftime_output, sizeof(strftime_output), "It is %Y-%m-%d %H:%M:%S", &tm); + std::strftime(strftime_output, sizeof(strftime_output), + "It is %Y-%m-%d %H:%M:%S", &tm); EXPECT_EQ(strftime_output, fmt::format("It is {:%Y-%m-%d %H:%M:%S}", point)); } @@ -246,25 +248,25 @@ TEST(ChronoTest, FormatSpecs) { TEST(ChronoTest, InvalidSpecs) { auto sec = std::chrono::seconds(0); - EXPECT_THROW_MSG(fmt::format("{:%a}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%A}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%c}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%x}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Ex}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%X}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%EX}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%D}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%F}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Ec}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%w}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%u}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%b}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%B}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%z}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Z}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error, + EXPECT_THROW_MSG(fmt::format(+"{:%a}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%A}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%c}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%x}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%Ex}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%X}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%EX}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%D}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%F}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%Ec}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%w}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%u}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%b}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%B}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%z}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%Z}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format(+"{:%Eq}", sec), fmt::format_error, "invalid format"); - EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error, + EXPECT_THROW_MSG(fmt::format(+"{:%Oq}", sec), fmt::format_error, "invalid format"); } @@ -307,7 +309,7 @@ TEST(ChronoTest, FormatDefaultFP) { } TEST(ChronoTest, FormatPrecision) { - EXPECT_THROW_MSG(fmt::format("{:.2}", std::chrono::seconds(42)), + EXPECT_THROW_MSG(fmt::format(+"{:.2}", std::chrono::seconds(42)), fmt::format_error, "precision not allowed for this argument type"); EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234))); @@ -334,7 +336,7 @@ TEST(ChronoTest, FormatSimpleQq) { } TEST(ChronoTest, FormatPrecisionQq) { - EXPECT_THROW_MSG(fmt::format("{:.2%Q %q}", std::chrono::seconds(42)), + EXPECT_THROW_MSG(fmt::format(+"{:.2%Q %q}", std::chrono::seconds(42)), fmt::format_error, "precision not allowed for this argument type"); EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234))); @@ -351,12 +353,12 @@ TEST(ChronoTest, FormatFullSpecsQq) { } TEST(ChronoTest, InvalidWidthId) { - EXPECT_THROW(fmt::format("{:{o}", std::chrono::seconds(0)), + EXPECT_THROW(fmt::format(+"{:{o}", std::chrono::seconds(0)), fmt::format_error); } TEST(ChronoTest, InvalidColons) { - EXPECT_THROW(fmt::format("{0}=:{0::", std::chrono::seconds(0)), + EXPECT_THROW(fmt::format(+"{0}=:{0::", std::chrono::seconds(0)), fmt::format_error); } diff --git a/test/core-test.cc b/test/core-test.cc index 5ae655e3..50b5f9b8 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -24,6 +24,9 @@ #endif #include "fmt/args.h" +#if defined(FMT_COMPILE_TIME_CHECKS) && FMT_COMPILE_TIME_CHECKS +# include "fmt/format.h" +#endif #undef min #undef max @@ -633,7 +636,7 @@ template <> struct formatter { }; template <> struct formatter { - auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } auto format(convertible_to_c_string, format_context& ctx) @@ -696,18 +699,10 @@ TYPED_TEST(IsStringTest, IsString) { } TEST(CoreTest, Format) { - // This should work without including fmt/format.h. -#ifdef FMT_FORMAT_H_ -# error fmt/format.h must not be included in the core test -#endif EXPECT_EQ(fmt::format("{}", 42), "42"); } TEST(CoreTest, FormatTo) { - // This should work without including fmt/format.h. -#ifdef FMT_FORMAT_H_ -# error fmt/format.h must not be included in the core test -#endif std::string s; fmt::format_to(std::back_inserter(s), "{}", 42); EXPECT_EQ(s, "42"); diff --git a/test/format-test.cc b/test/format-test.cc index 94a13507..0a5bc0a8 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -521,9 +521,10 @@ TEST(FormatterTest, Escape) { } TEST(FormatterTest, UnmatchedBraces) { - EXPECT_THROW_MSG(format("{"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("}"), format_error, "unmatched '}' in format string"); - EXPECT_THROW_MSG(format("{0{}"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"}"), format_error, + "unmatched '}' in format string"); + EXPECT_THROW_MSG(format(+"{0{}"), format_error, "invalid format string"); } TEST(FormatterTest, NoArgs) { EXPECT_EQ("test", format("test")); } @@ -539,22 +540,22 @@ TEST(FormatterTest, ArgsInDifferentPositions) { } TEST(FormatterTest, ArgErrors) { - EXPECT_THROW_MSG(format("{"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{?}"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0}"), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{00}", 42), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{?}"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{0"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{0}"), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+"{00}", 42), format_error, "invalid format string"); char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{%u", INT_MAX); - EXPECT_THROW_MSG(format(format_str), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+format_str), format_error, "invalid format string"); safe_sprintf(format_str, "{%u}", INT_MAX); - EXPECT_THROW_MSG(format(format_str), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+format_str), format_error, "argument not found"); safe_sprintf(format_str, "{%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str), format_error, "number is too big"); safe_sprintf(format_str, "{%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str), format_error, "number is too big"); } template struct TestFormat { @@ -595,22 +596,22 @@ TEST(FormatterTest, NamedArg) { fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0), fmt::arg("l", 0), fmt::arg("m", 0), fmt::arg("n", 0), fmt::arg("o", 0), fmt::arg("p", 0))); - EXPECT_THROW_MSG(format("{a}"), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{a}", 42), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+"{a}"), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+"{a}", 42), format_error, "argument not found"); } TEST(FormatterTest, AutoArgIndex) { EXPECT_EQ("abc", format("{}{}{}", 'a', 'b', 'c')); - EXPECT_THROW_MSG(format("{0}{}", 'a', 'b'), format_error, + EXPECT_THROW_MSG(format(+"{0}{}", 'a', 'b'), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{}{0}", 'a', 'b'), format_error, + EXPECT_THROW_MSG(format(+"{}{0}", 'a', 'b'), format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_EQ("1.2", format("{:.{}}", 1.2345, 2)); - EXPECT_THROW_MSG(format("{0}:.{}", 1.2345, 2), format_error, + EXPECT_THROW_MSG(format(+"{0}:.{}", 1.2345, 2), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{:.{0}}", 1.2345, 2), format_error, + EXPECT_THROW_MSG(format(+"{:.{0}}", 1.2345, 2), format_error, "cannot switch from automatic to manual argument indexing"); - EXPECT_THROW_MSG(format("{}"), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+"{}"), format_error, "argument not found"); } TEST(FormatterTest, EmptySpecs) { EXPECT_EQ("42", format("{0:}", 42)); } @@ -671,9 +672,9 @@ TEST(FormatterTest, CenterAlign) { } TEST(FormatterTest, Fill) { - EXPECT_THROW_MSG(format("{0:{<5}", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:{<5}", 'c'), format_error, "invalid fill character '{'"); - EXPECT_THROW_MSG(format("{0:{<5}}", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:{<5}}", 'c'), format_error, "invalid fill character '{'"); EXPECT_EQ("**42", format("{0:*>4}", 42)); EXPECT_EQ("**-42", format("{0:*>5}", -42)); @@ -690,7 +691,7 @@ TEST(FormatterTest, Fill) { EXPECT_EQ("foo=", format("{:}=", "foo")); EXPECT_EQ(std::string("\0\0\0*", 4), format(string_view("{:\0>4}", 6), '*')); EXPECT_EQ("жж42", format("{0:ж>4}", 42)); - EXPECT_THROW_MSG(format("{:\x80\x80\x80\x80\x80>}", 0), format_error, + EXPECT_THROW_MSG(format(+"{:\x80\x80\x80\x80\x80>}", 0), format_error, "missing '}' in format string"); } @@ -698,72 +699,72 @@ TEST(FormatterTest, PlusSign) { EXPECT_EQ("+42", format("{0:+}", 42)); EXPECT_EQ("-42", format("{0:+}", -42)); EXPECT_EQ("+42", format("{0:+}", 42)); - EXPECT_THROW_MSG(format("{0:+}", 42u), format_error, + EXPECT_THROW_MSG(format(+"{0:+}", 42u), format_error, "format specifier requires signed argument"); EXPECT_EQ("+42", format("{0:+}", 42l)); - EXPECT_THROW_MSG(format("{0:+}", 42ul), format_error, + EXPECT_THROW_MSG(format(+"{0:+}", 42ul), format_error, "format specifier requires signed argument"); EXPECT_EQ("+42", format("{0:+}", 42ll)); - EXPECT_THROW_MSG(format("{0:+}", 42ull), format_error, + EXPECT_THROW_MSG(format(+"{0:+}", 42ull), format_error, "format specifier requires signed argument"); EXPECT_EQ("+42", format("{0:+}", 42.0)); EXPECT_EQ("+42", format("{0:+}", 42.0l)); - EXPECT_THROW_MSG(format("{0:+", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:+", 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:+}", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:+}", 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:+}", "abc"), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast(0x42)), format_error, + EXPECT_THROW_MSG(format(+"{0:+}", "abc"), format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG(format(+"{0:+}", reinterpret_cast(0x42)), + format_error, "format specifier requires numeric argument"); } TEST(FormatterTest, MinusSign) { EXPECT_EQ("42", format("{0:-}", 42)); EXPECT_EQ("-42", format("{0:-}", -42)); EXPECT_EQ("42", format("{0:-}", 42)); - EXPECT_THROW_MSG(format("{0:-}", 42u), format_error, + EXPECT_THROW_MSG(format(+"{0:-}", 42u), format_error, "format specifier requires signed argument"); EXPECT_EQ("42", format("{0:-}", 42l)); - EXPECT_THROW_MSG(format("{0:-}", 42ul), format_error, + EXPECT_THROW_MSG(format(+"{0:-}", 42ul), format_error, "format specifier requires signed argument"); EXPECT_EQ("42", format("{0:-}", 42ll)); - EXPECT_THROW_MSG(format("{0:-}", 42ull), format_error, + EXPECT_THROW_MSG(format(+"{0:-}", 42ull), format_error, "format specifier requires signed argument"); EXPECT_EQ("42", format("{0:-}", 42.0)); EXPECT_EQ("42", format("{0:-}", 42.0l)); - EXPECT_THROW_MSG(format("{0:-", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:-", 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:-}", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:-}", 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:-}", "abc"), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast(0x42)), format_error, + EXPECT_THROW_MSG(format(+"{0:-}", "abc"), format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG(format(+"{0:-}", reinterpret_cast(0x42)), + format_error, "format specifier requires numeric argument"); } TEST(FormatterTest, SpaceSign) { EXPECT_EQ(" 42", format("{0: }", 42)); EXPECT_EQ("-42", format("{0: }", -42)); EXPECT_EQ(" 42", format("{0: }", 42)); - EXPECT_THROW_MSG(format("{0: }", 42u), format_error, + EXPECT_THROW_MSG(format(+"{0: }", 42u), format_error, "format specifier requires signed argument"); EXPECT_EQ(" 42", format("{0: }", 42l)); - EXPECT_THROW_MSG(format("{0: }", 42ul), format_error, + EXPECT_THROW_MSG(format(+"{0: }", 42ul), format_error, "format specifier requires signed argument"); EXPECT_EQ(" 42", format("{0: }", 42ll)); - EXPECT_THROW_MSG(format("{0: }", 42ull), format_error, + EXPECT_THROW_MSG(format(+"{0: }", 42ull), format_error, "format specifier requires signed argument"); EXPECT_EQ(" 42", format("{0: }", 42.0)); EXPECT_EQ(" 42", format("{0: }", 42.0l)); - EXPECT_THROW_MSG(format("{0: ", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0: ", 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0: }", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0: }", 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0: }", "abc"), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0: }", reinterpret_cast(0x42)), format_error, + EXPECT_THROW_MSG(format(+"{0: }", "abc"), format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG(format(+"{0: }", reinterpret_cast(0x42)), + format_error, "format specifier requires numeric argument"); } TEST(FormatterTest, SignNotTruncated) { @@ -812,14 +813,14 @@ TEST(FormatterTest, HashFlag) { EXPECT_EQ("0.", format("{:#.0f}", 0.01)); EXPECT_EQ("0.50", format("{:#.2g}", 0.5)); EXPECT_EQ("0.", format("{:#.0f}", 0.5)); - EXPECT_THROW_MSG(format("{0:#", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:#", 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:#}", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:#}", 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:#}", "abc"), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast(0x42)), format_error, + EXPECT_THROW_MSG(format(+"{0:#}", "abc"), format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG(format(+"{0:#}", reinterpret_cast(0x42)), + format_error, "format specifier requires numeric argument"); } TEST(FormatterTest, ZeroFlag) { @@ -832,13 +833,13 @@ TEST(FormatterTest, ZeroFlag) { EXPECT_EQ("00042", format("{0:05}", 42ull)); EXPECT_EQ("-000042", format("{0:07}", -42.0)); EXPECT_EQ("-000042", format("{0:07}", -42.0l)); - EXPECT_THROW_MSG(format("{0:0", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:0", 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:05}", 'c'), format_error, + EXPECT_THROW_MSG(format(+"{0:05}", 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:05}", "abc"), format_error, + EXPECT_THROW_MSG(format(+"{0:05}", "abc"), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast(0x42)), + EXPECT_THROW_MSG(format(+"{0:05}", reinterpret_cast(0x42)), format_error, "format specifier requires numeric argument"); } @@ -846,16 +847,16 @@ TEST(FormatterTest, Width) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:%u", UINT_MAX); increment(format_str + 3); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); EXPECT_EQ(" -42", format("{0:4}", -42)); EXPECT_EQ(" 42", format("{0:5}", 42u)); EXPECT_EQ(" -42", format("{0:6}", -42l)); @@ -876,39 +877,40 @@ TEST(FormatterTest, RuntimeWidth) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:{%u", UINT_MAX); increment(format_str + 4); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); format_str[size + 1] = '}'; format_str[size + 2] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:{", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:{}", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:{", 0), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{0:{}", 0), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{0:{?}}", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:{1}}", 0), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+"{0:{?}}", 0), format_error, + "invalid format string"); + EXPECT_THROW_MSG(format(+"{0:{1}}", 0), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{0:{0:}}", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:{0:}}", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, -1), format_error, "negative width"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, (INT_MAX + 1u)), format_error, + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, -1), format_error, "negative width"); + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, (INT_MAX + 1u)), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, -1l), format_error, "negative width"); + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, -1l), format_error, "negative width"); if (const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; - EXPECT_THROW_MSG(format("{0:{1}}", 0, (value + 1)), format_error, + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, (value + 1)), format_error, "number is too big"); } - EXPECT_THROW_MSG(format("{0:{1}}", 0, (INT_MAX + 1ul)), format_error, + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, (INT_MAX + 1ul)), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, '0'), format_error, + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, '0'), format_error, "width is not integer"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, 0.0), format_error, + EXPECT_THROW_MSG(format(+"{0:{1}}", 0, 0.0), format_error, "width is not integer"); EXPECT_EQ(" -42", format("{0:{1}}", -42, 4)); @@ -929,49 +931,49 @@ TEST(FormatterTest, Precision) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:.%u", UINT_MAX); increment(format_str + 4); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:.%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:.%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:.", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.", 0), format_error, "missing precision specifier"); - EXPECT_THROW_MSG(format("{0:.}", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.}", 0), format_error, "missing precision specifier"); - EXPECT_THROW_MSG(format("{0:.2", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.2", 0), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42), format_error, + EXPECT_THROW_MSG(format(+"{0:.2}", 42), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42), format_error, + EXPECT_THROW_MSG(format(+"{0:.2f}", 42), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42u), format_error, + EXPECT_THROW_MSG(format(+"{0:.2}", 42u), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42u), format_error, + EXPECT_THROW_MSG(format(+"{0:.2f}", 42u), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42l), format_error, + EXPECT_THROW_MSG(format(+"{0:.2}", 42l), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42l), format_error, + EXPECT_THROW_MSG(format(+"{0:.2f}", 42l), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42ul), format_error, + EXPECT_THROW_MSG(format(+"{0:.2}", 42ul), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42ul), format_error, + EXPECT_THROW_MSG(format(+"{0:.2f}", 42ul), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42ll), format_error, + EXPECT_THROW_MSG(format(+"{0:.2}", 42ll), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42ll), format_error, + EXPECT_THROW_MSG(format(+"{0:.2f}", 42ll), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42ull), format_error, + EXPECT_THROW_MSG(format(+"{0:.2}", 42ull), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42ull), format_error, + EXPECT_THROW_MSG(format(+"{0:.2f}", 42ull), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:3.0}", 'x'), format_error, + EXPECT_THROW_MSG(format(+"{0:3.0}", 'x'), 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)); @@ -1008,13 +1010,13 @@ TEST(FormatterTest, Precision) { EXPECT_EQ("1e+01", format("{:.0e}", 9.5)); EXPECT_EQ("1.0e-34", fmt::format("{:.1e}", 1e-34)); - EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast(0xcafe)), + EXPECT_THROW_MSG(format(+"{0:.2}", reinterpret_cast(0xcafe)), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", reinterpret_cast(0xcafe)), + EXPECT_THROW_MSG(format(+"{0:.2f}", reinterpret_cast(0xcafe)), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{:.{}e}", 42.0, fmt::detail::max_value()), + EXPECT_THROW_MSG(format(+"{:.{}e}", 42.0, fmt::detail::max_value()), format_error, "number is too big"); EXPECT_EQ("st", format("{0:.2}", "str")); @@ -1024,79 +1026,79 @@ TEST(FormatterTest, RuntimePrecision) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:.{%u", UINT_MAX); increment(format_str + 5); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); format_str[size + 1] = '}'; format_str[size + 2] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG(format(+format_str, 0), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:.{", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:.{}", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.{", 0), format_error, "invalid format string"); + EXPECT_THROW_MSG(format(+"{0:.{}", 0), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{0:.{?}}", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.{?}}", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:.{1}", 0, 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}", 0, 0), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0), format_error, "argument not found"); + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{0:.{0:}}", 0), format_error, + EXPECT_THROW_MSG(format(+"{0:.{0:}}", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, -1), format_error, "negative precision"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1u)), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, (INT_MAX + 1u)), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, -1l), format_error, "negative precision"); if (const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; - EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, (value + 1)), format_error, "number is too big"); } - EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1ul)), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, (INT_MAX + 1ul)), format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, '0'), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, '0'), format_error, "precision is not integer"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, 0.0), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 0, 0.0), format_error, "precision is not integer"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 42, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}f}", 42, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42u, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 42u, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42u, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}f}", 42u, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42l, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 42l, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42l, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}f}", 42l, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42ul, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 42ul, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42ul, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}f}", 42ul, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42ll, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 42ll, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42ll, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}f}", 42ll, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42ull, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}}", 42ull, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42ull, 2), format_error, + EXPECT_THROW_MSG(format(+"{0:.{1}f}", 42ull, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:3.{1}}", 'x', 0), format_error, + EXPECT_THROW_MSG(format(+"{0:3.{1}}", 'x', 0), 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), + EXPECT_THROW_MSG(format(+"{0:.{1}}", reinterpret_cast(0xcafe), 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", reinterpret_cast(0xcafe), 2), + EXPECT_THROW_MSG(format(+"{0:.{1}f}", reinterpret_cast(0xcafe), 2), format_error, "precision not allowed for this argument type"); @@ -1112,7 +1114,7 @@ void check_unknown_types(const T& value, const char* types, const char*) { if (std::strchr(types, c) || std::strchr(special, c) || !c) continue; safe_sprintf(format_str, "{0:10%c}", c); const char* message = "invalid type specifier"; - EXPECT_THROW_MSG(format(format_str, value), format_error, message) + EXPECT_THROW_MSG(format(+format_str, value), format_error, message) << format_str << " " << message; } } @@ -1133,7 +1135,7 @@ TEST(FormatterTest, FormatShort) { } TEST(FormatterTest, FormatInt) { - EXPECT_THROW_MSG(format("{0:v", 42), format_error, + EXPECT_THROW_MSG(format(+"{0:v", 42), format_error, "missing '}' in format string"); check_unknown_types(42, "bBdoxXnLc", "integer"); EXPECT_EQ("x", format("{:c}", static_cast('x'))); @@ -1437,7 +1439,7 @@ TEST(FormatterTest, FormatCString) { EXPECT_EQ("test", format("{0:s}", "test")); char nonconst[] = "nonconst"; EXPECT_EQ("nonconst", format("{0}", nonconst)); - EXPECT_THROW_MSG(format("{0}", static_cast(nullptr)), + EXPECT_THROW_MSG(format(+"{0}", static_cast(nullptr)), format_error, "string pointer is null"); } @@ -1570,7 +1572,7 @@ FMT_END_NAMESPACE TEST(FormatterTest, FormatCustom) { Date date(2012, 12, 9); - EXPECT_THROW_MSG(fmt::format("{:s}", date), format_error, + EXPECT_THROW_MSG(fmt::format(+"{:s}", date), format_error, "unknown format specifier"); } @@ -1669,7 +1671,7 @@ TEST(FormatterTest, Examples) { format("int: {0:d}; hex: {0:#x}; oct: {0:#o}", 42)); EXPECT_EQ("The answer is 42", format("The answer is {}", 42)); - EXPECT_THROW_MSG(format("The answer is {:d}", "forty-two"), format_error, + EXPECT_THROW_MSG(format(+"The answer is {:d}", "forty-two"), format_error, "invalid type specifier"); EXPECT_EQ(L"Cyrillic letter \x42e", format(L"Cyrillic letter {}", L'\x42e')); @@ -1931,25 +1933,25 @@ TEST(FormatTest, DynamicFormatter) { EXPECT_EQ("42", format("{:d}", num)); EXPECT_EQ("foo", format("{:s}", str)); EXPECT_EQ(" 42 foo ", format("{:{}} {:{}}", num, 3, str, 4)); - EXPECT_THROW_MSG(format("{0:{}}", num), format_error, + EXPECT_THROW_MSG(format(+"{0:{}}", num), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{:{0}}", num), format_error, + EXPECT_THROW_MSG(format(+"{:{0}}", num), format_error, "cannot switch from automatic to manual argument indexing"); #if FMT_DEPRECATED_NUMERIC_ALIGN - EXPECT_THROW_MSG(format("{:=}", str), format_error, + EXPECT_THROW_MSG(format(+"{:=}", str), format_error, "format specifier requires numeric argument"); #endif - EXPECT_THROW_MSG(format("{:+}", str), format_error, + EXPECT_THROW_MSG(format(+"{:+}", str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:-}", str), format_error, + EXPECT_THROW_MSG(format(+"{:-}", str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{: }", str), format_error, + EXPECT_THROW_MSG(format(+"{: }", str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:#}", str), format_error, + EXPECT_THROW_MSG(format(+"{:#}", str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:0}", str), format_error, + EXPECT_THROW_MSG(format(+"{:0}", str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:.2}", num), format_error, + EXPECT_THROW_MSG(format(+"{:.2}", num), format_error, "precision not allowed for this argument type"); } diff --git a/test/locale-test.cc b/test/locale-test.cc index 672c6b28..143348d1 100644 --- a/test/locale-test.cc +++ b/test/locale-test.cc @@ -115,7 +115,7 @@ template struct formatter, charT> { detail::dynamic_format_specs specs_; public: - typename basic_format_parse_context::iterator parse( + FMT_CONSTEXPR typename basic_format_parse_context::iterator parse( basic_format_parse_context& ctx) { using handler_type = detail::dynamic_specs_handler>; diff --git a/test/ostream-test.cc b/test/ostream-test.cc index ec9508e3..bd93a17c 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -97,20 +97,20 @@ TEST(OStreamTest, FormatSpecs) { EXPECT_EQ("def ", format("{0:<5}", TestString("def"))); EXPECT_EQ(" def", format("{0:>5}", TestString("def"))); #if FMT_DEPRECATED_NUMERIC_ALIGN - EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), format_error, + EXPECT_THROW_MSG(format(+"{0:=5}", TestString("def")), format_error, "format specifier requires numeric argument"); #endif EXPECT_EQ(" def ", format("{0:^5}", TestString("def"))); EXPECT_EQ("def**", format("{0:*<5}", TestString("def"))); - EXPECT_THROW_MSG(format("{0:+}", TestString()), format_error, + EXPECT_THROW_MSG(format(+"{0:+}", TestString()), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:-}", TestString()), format_error, + EXPECT_THROW_MSG(format(+"{0:-}", TestString()), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0: }", TestString()), format_error, + EXPECT_THROW_MSG(format(+"{0: }", TestString()), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:#}", TestString()), format_error, + EXPECT_THROW_MSG(format(+"{0:#}", TestString()), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:05}", TestString()), format_error, + EXPECT_THROW_MSG(format(+"{0:05}", TestString()), format_error, "format specifier requires numeric argument"); EXPECT_EQ("test ", format("{0:13}", TestString("test"))); EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));