mirror of
https://github.com/fmtlib/fmt.git
synced 2026-10-28 18:07:37 +08:00
Fix formatting of nullptr with FMT_COMPILE and to_string (#4993)
* Fix formatting of nullptr with FMT_COMPILE and to_string
std::nullptr_t is implicitly convertible to string_view and const char*,
so compiled format strings and fmt::to_string treated nullptr as a null
C string: FMT_COMPILE("{}!") crashed and FMT_COMPILE("{}") and to_string
threw "string pointer is null". Format it as a pointer ("0x0") like the
runtime API does.
* Write nullptr as a pointer in detail::write
detail::write<Char>(out, nullptr) picked the const Char* overload, so
fmt::to_string(nullptr) and FMT_COMPILE("{}") threw "string pointer is
null". Add a nullptr_t overload that forwards to the const void* one.
This commit is contained in:
parent
3a2dcb59ef
commit
2e60743c67
@ -175,7 +175,8 @@ template <typename Char, typename V, int N> struct field {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
const V& arg = get_arg_checked<V, N>(args...);
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value) {
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value &&
|
||||
!std::is_same<V, nullptr_t>::value) {
|
||||
auto s = basic_string_view<Char>(arg);
|
||||
return copy<Char>(s.begin(), s.end(), out);
|
||||
} else if constexpr (use_format_as<V>::value) {
|
||||
|
||||
@ -3920,6 +3920,11 @@ auto write(OutputIt out, const T* value, const format_specs& specs = {},
|
||||
return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write(OutputIt out, nullptr_t) -> OutputIt {
|
||||
return write<Char>(out, static_cast<const void*>(nullptr));
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(mapped_type_constant<T, Char>::value ==
|
||||
type::custom_type &&
|
||||
|
||||
@ -76,6 +76,7 @@ TEST(compile_test, format_default) {
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable()));
|
||||
EXPECT_EQ("0x0", fmt::format(FMT_COMPILE("{}"), nullptr));
|
||||
auto t = std::chrono::system_clock::now();
|
||||
EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t));
|
||||
}
|
||||
@ -314,6 +315,7 @@ TEST(compile_test, static_format_high_precision) {
|
||||
TEST(compile_test, text_and_arg) {
|
||||
EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
|
||||
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
|
||||
EXPECT_EQ("0x0!", fmt::format(FMT_COMPILE("{}!"), nullptr));
|
||||
}
|
||||
|
||||
TEST(compile_test, unknown_format_fallback) {
|
||||
|
||||
@ -2339,6 +2339,7 @@ FMT_END_NAMESPACE
|
||||
TEST(format_test, to_string) {
|
||||
EXPECT_EQ(fmt::to_string(42), "42");
|
||||
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
|
||||
EXPECT_EQ(fmt::to_string(nullptr), "0x0");
|
||||
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo");
|
||||
EXPECT_EQ(fmt::to_string(foo), "0");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user