Fix error reporting when mixing character types

This commit is contained in:
Victor Zverovich 2021-08-26 17:36:29 -07:00
parent 117fc67077
commit 8b0cb944da
2 changed files with 46 additions and 19 deletions

View File

@ -1128,6 +1128,7 @@ constexpr bool is_arithmetic_type(type t) {
struct unformattable {};
struct unformattable_pointer : unformattable {};
struct unformattable_char : unformattable {};
template <typename Char> struct string_value {
const Char* data;
@ -1207,6 +1208,7 @@ template <typename Context> 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 <typename Context> 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 <typename T, FMT_ENABLE_IF(is_char<T>::value)>
template <typename T, FMT_ENABLE_IF(std::is_same<T, char>::value ||
std::is_same<T, char_type>::value)>
FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type {
static_assert(
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
"mixing character types is disallowed");
return val;
}
template <typename T, FMT_ENABLE_IF(std::is_same<T, wchar_t>::value &&
!std::is_same<wchar_t, char_type>::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 <typename Context> struct arg_mapper {
return val;
}
template <typename T,
FMT_ENABLE_IF(is_string<T>::value && !std::is_pointer<T>::value)>
FMT_ENABLE_IF(is_string<T>::value && !std::is_pointer<T>::value &&
std::is_same<char_type, char_t<T>>::value)>
FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
-> basic_string_view<char_type> {
static_assert(std::is_same<char_type, char_t<T>>::value,
"mixing character types is disallowed");
return to_string_view(val);
}
template <typename T,
FMT_ENABLE_IF(is_string<T>::value && !std::is_pointer<T>::value &&
!std::is_same<char_type, char_t<T>>::value)>
FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char {
return {};
}
template <typename T,
FMT_ENABLE_IF(
std::is_constructible<basic_string_view<char_type>, T>::value &&
@ -1308,21 +1318,21 @@ template <typename Context> struct arg_mapper {
-> basic_string_view<char_type> {
return std_string_view<char_type>(val);
}
FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* {
static_assert(std::is_same<char_type, char>::value, "invalid string type");
return reinterpret_cast<const char*>(val);
FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val)
-> decltype(this->map("")) {
return map(reinterpret_cast<const char*>(val));
}
FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* {
static_assert(std::is_same<char_type, char>::value, "invalid string type");
return reinterpret_cast<const char*>(val);
FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val)
-> decltype(this->map("")) {
return map(reinterpret_cast<const char*>(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<const char*>(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<const char*>(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<Context> {
constexpr bool void_ptr =
!std::is_same<decltype(arg), const unformattable_pointer&>::value;
static_assert(void_ptr, "Formatting of non-void pointers is disallowed.");
constexpr bool same_char =
!std::is_same<decltype(arg), const unformattable_char&>::value;
static_assert(same_char, "Mixing character types is disallowed.");
constexpr bool formattable =
!std::is_same<decltype(arg), const unformattable&>::value;
static_assert(

View File

@ -704,11 +704,23 @@ TEST(core_test, has_formatter) {
}
TEST(core_test, is_formattable) {
static_assert(fmt::is_formattable<signed char*>::value, "");
static_assert(fmt::is_formattable<unsigned char*>::value, "");
static_assert(fmt::is_formattable<const signed char*>::value, "");
static_assert(fmt::is_formattable<const unsigned char*>::value, "");
static_assert(!fmt::is_formattable<wchar_t>::value, "");
static_assert(!fmt::is_formattable<const wchar_t*>::value, "");
static_assert(!fmt::is_formattable<const wchar_t[3]>::value, "");
static_assert(!fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value,
"");
static_assert(fmt::is_formattable<enabled_formatter>::value, "");
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, "");
static_assert(!fmt::is_formattable<signed char*, wchar_t>::value, "");
static_assert(!fmt::is_formattable<unsigned char*, wchar_t>::value, "");
static_assert(!fmt::is_formattable<const signed char*, wchar_t>::value, "");
static_assert(!fmt::is_formattable<const unsigned char*, wchar_t>::value, "");
}
TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }