From 8b0cb944dad7701f719281fa11cae488324b53e7 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 26 Aug 2021 17:36:29 -0700 Subject: [PATCH] Fix error reporting when mixing character types --- include/fmt/core.h | 53 +++++++++++++++++++++++++++++----------------- test/core-test.cc | 12 +++++++++++ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index b0405ee4..a0d86d06 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1128,6 +1128,7 @@ constexpr bool is_arithmetic_type(type t) { struct unformattable {}; struct unformattable_pointer : unformattable {}; +struct unformattable_char : unformattable {}; template struct string_value { const Char* data; @@ -1207,6 +1208,7 @@ template class value { } value(unformattable); value(unformattable_pointer); + value(unformattable_char); private: // Formats an argument of a custom type, such as a user-defined class. @@ -1260,13 +1262,16 @@ template struct arg_mapper { FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } - template ::value)> + template ::value || + std::is_same::value)> FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { - static_assert( - std::is_same::value || std::is_same::value, - "mixing character types is disallowed"); return val; } + template ::value && + !std::is_same::value)> + FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { + return {}; + } FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } @@ -1281,13 +1286,18 @@ template struct arg_mapper { return val; } template ::value && !std::is_pointer::value)> + FMT_ENABLE_IF(is_string::value && !std::is_pointer::value && + std::is_same>::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> basic_string_view { - static_assert(std::is_same>::value, - "mixing character types is disallowed"); return to_string_view(val); } + template ::value && !std::is_pointer::value && + !std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { + return {}; + } template , T>::value && @@ -1308,21 +1318,21 @@ template struct arg_mapper { -> basic_string_view { return std_string_view(val); } - FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); + FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) + -> decltype(this->map("")) { + return map(reinterpret_cast(val)); } - FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); + FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) + -> decltype(this->map("")) { + return map(reinterpret_cast(val)); } - FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> const char* { - const auto* const_val = val; - return map(const_val); + FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) + -> decltype(this->map("")) { + return map(reinterpret_cast(val)); } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> const char* { - const auto* const_val = val; - return map(const_val); + FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) + -> decltype(this->map("")) { + return map(reinterpret_cast(val)); } FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } @@ -1609,6 +1619,11 @@ FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value { constexpr bool void_ptr = !std::is_same::value; static_assert(void_ptr, "Formatting of non-void pointers is disallowed."); + + constexpr bool same_char = + !std::is_same::value; + static_assert(same_char, "Mixing character types is disallowed."); + constexpr bool formattable = !std::is_same::value; static_assert( diff --git a/test/core-test.cc b/test/core-test.cc index 7e490b56..12b28964 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -704,11 +704,23 @@ TEST(core_test, has_formatter) { } TEST(core_test, is_formattable) { + static_assert(fmt::is_formattable::value, ""); + static_assert(fmt::is_formattable::value, ""); + static_assert(fmt::is_formattable::value, ""); + static_assert(fmt::is_formattable::value, ""); + static_assert(!fmt::is_formattable::value, ""); static_assert(!fmt::is_formattable::value, ""); static_assert(!fmt::is_formattable::value, ""); + static_assert(!fmt::is_formattable>::value, + ""); static_assert(fmt::is_formattable::value, ""); static_assert(!fmt::is_formattable::value, ""); static_assert(fmt::is_formattable::value, ""); + + static_assert(!fmt::is_formattable::value, ""); + static_assert(!fmt::is_formattable::value, ""); + static_assert(!fmt::is_formattable::value, ""); + static_assert(!fmt::is_formattable::value, ""); } TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }