Fix error reporting when mixing character types
This commit is contained in:
parent
117fc67077
commit
8b0cb944da
@ -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(
|
||||
|
@ -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"); }
|
||||
|
Loading…
Reference in New Issue
Block a user