From ea3e747eea7d5bf345a9591d27a751a8ec9b794a Mon Sep 17 00:00:00 2001 From: gabime Date: Fri, 28 Nov 2025 19:00:23 +0200 Subject: [PATCH] Bump fmt to 12.1.0 --- include/spdlog/fmt/bundled/base.h | 34 +++-- include/spdlog/fmt/bundled/chrono.h | 9 +- include/spdlog/fmt/bundled/color.h | 2 +- include/spdlog/fmt/bundled/compile.h | 5 +- include/spdlog/fmt/bundled/format-inl.h | 7 +- include/spdlog/fmt/bundled/format.h | 28 ++-- include/spdlog/fmt/bundled/os.h | 17 ++- include/spdlog/fmt/bundled/ranges.h | 19 ++- include/spdlog/fmt/bundled/std.h | 164 +++++++++++++----------- src/bundled_fmtlib_format.cpp | 14 +- 10 files changed, 176 insertions(+), 123 deletions(-) diff --git a/include/spdlog/fmt/bundled/base.h b/include/spdlog/fmt/bundled/base.h index 42e192ac..0d578677 100644 --- a/include/spdlog/fmt/bundled/base.h +++ b/include/spdlog/fmt/bundled/base.h @@ -21,7 +21,7 @@ #endif // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 120000 +#define FMT_VERSION 120100 // Detect compiler versions. #if defined(__clang__) && !defined(__ibmxl__) @@ -114,7 +114,9 @@ #endif // Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated. -#if !defined(__cpp_lib_is_constant_evaluated) +#ifdef FMT_USE_CONSTEVAL +// Use the provided definition. +#elif !defined(__cpp_lib_is_constant_evaluated) # define FMT_USE_CONSTEVAL 0 #elif FMT_CPLUSPLUS < 201709L # define FMT_USE_CONSTEVAL 0 @@ -234,6 +236,7 @@ FMT_PRAGMA_GCC(optimize("Og")) # define FMT_GCC_OPTIMIZED #endif FMT_PRAGMA_CLANG(diagnostic push) +FMT_PRAGMA_GCC(diagnostic push) #ifdef FMT_ALWAYS_INLINE // Use the provided definition. @@ -414,8 +417,12 @@ inline auto map(int128_opt) -> monostate { return {}; } inline auto map(uint128_opt) -> monostate { return {}; } #endif -#ifndef FMT_USE_BITINT -# define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500) +#ifdef FMT_USE_BITINT +// Use the provided definition. +#elif FMT_CLANG_VERSION >= 1500 && !defined(__CUDACC__) +# define FMT_USE_BITINT 1 +#else +# define FMT_USE_BITINT 0 #endif #if FMT_USE_BITINT @@ -918,7 +925,10 @@ class locale_ref { constexpr locale_ref() : locale_(nullptr) {} template - locale_ref(const Locale& loc); + locale_ref(const Locale& loc) : locale_(&loc) { + // Check if std::isalpha is found via ADL to reduce the chance of misuse. + isalpha('x', loc); + } inline explicit operator bool() const noexcept { return locale_ != nullptr; } #endif // FMT_USE_LOCALE @@ -1844,12 +1854,17 @@ template class buffer { void append(const U* begin, const U* end) { while (begin != end) { + auto size = size_; + auto free_cap = capacity_ - size; auto count = to_unsigned(end - begin); - try_reserve(size_ + count); - auto free_cap = capacity_ - size_; - if (free_cap < count) count = free_cap; + if (free_cap < count) { + grow_(*this, size + count); + size = size_; + free_cap = capacity_ - size; + count = count < free_cap ? count : free_cap; + } // A loop is faster than memcpy on small sizes. - T* out = ptr_ + size_; + T* out = ptr_ + size; for (size_t i = 0; i < count; ++i) out[i] = begin[i]; size_ += count; begin += count; @@ -2983,6 +2998,7 @@ FMT_INLINE void println(format_string fmt, T&&... args) { return fmt::println(stdout, fmt, static_cast(args)...); } +FMT_PRAGMA_GCC(diagnostic pop) FMT_PRAGMA_CLANG(diagnostic pop) FMT_PRAGMA_GCC(pop_options) FMT_END_EXPORT diff --git a/include/spdlog/fmt/bundled/chrono.h b/include/spdlog/fmt/bundled/chrono.h index a788d3ec..9fbeeed6 100644 --- a/include/spdlog/fmt/bundled/chrono.h +++ b/include/spdlog/fmt/bundled/chrono.h @@ -1594,8 +1594,13 @@ class get_locale { public: inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) { - if (localized) - ::new (&locale_) std::locale(loc.template get()); + if (!localized) return; + ignore_unused(loc); + ::new (&locale_) std::locale( +#if FMT_USE_LOCALE + loc.template get() +#endif + ); } inline ~get_locale() { if (has_locale_) locale_.~locale(); diff --git a/include/spdlog/fmt/bundled/color.h b/include/spdlog/fmt/bundled/color.h index b69c1488..2cbc53ca 100644 --- a/include/spdlog/fmt/bundled/color.h +++ b/include/spdlog/fmt/bundled/color.h @@ -429,7 +429,7 @@ template struct ansi_color_escape { private: static constexpr size_t num_emphases = 8; - Char buffer[7u + 4u * num_emphases]; + Char buffer[7u + 4u * num_emphases] = {}; size_t size = 0; static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, diff --git a/include/spdlog/fmt/bundled/compile.h b/include/spdlog/fmt/bundled/compile.h index f711ba41..64eb7a20 100644 --- a/include/spdlog/fmt/bundled/compile.h +++ b/include/spdlog/fmt/bundled/compile.h @@ -15,9 +15,10 @@ #include "format.h" FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT // A compile-time string which is compiled into fast formatting code. -FMT_EXPORT class compiled_string {}; +class compiled_string {}; template struct is_compiled_string : std::is_base_of {}; @@ -59,6 +60,8 @@ template constexpr auto operator""_cf() { } // namespace literals #endif +FMT_END_EXPORT + namespace detail { template diff --git a/include/spdlog/fmt/bundled/format-inl.h b/include/spdlog/fmt/bundled/format-inl.h index 9d568dca..945cb912 100644 --- a/include/spdlog/fmt/bundled/format-inl.h +++ b/include/spdlog/fmt/bundled/format-inl.h @@ -36,7 +36,7 @@ FMT_BEGIN_NAMESPACE FMT_FUNC void assert_fail(const char* file, int line, const char* message) { // Use unchecked std::fprintf to avoid triggering another assertion when // writing to stderr fails. - fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); + std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); abort(); } #endif @@ -47,11 +47,6 @@ using std::locale; using std::numpunct; using std::use_facet; } // namespace detail - -template > -locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { - static_assert(std::is_same::value, ""); -} #else namespace detail { struct locale {}; diff --git a/include/spdlog/fmt/bundled/format.h b/include/spdlog/fmt/bundled/format.h index c3a1bda0..4a653007 100644 --- a/include/spdlog/fmt/bundled/format.h +++ b/include/spdlog/fmt/bundled/format.h @@ -40,11 +40,18 @@ #include "base.h" +// libc++ supports string_view in pre-c++17. +#if FMT_HAS_INCLUDE() && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# define FMT_USE_STRING_VIEW +#endif + #ifndef FMT_MODULE +# include // malloc, free + # include // std::signbit # include // std::byte # include // uint32_t -# include // std::malloc, std::free # include // std::memcpy # include // std::numeric_limits # include // std::bad_alloc @@ -61,11 +68,8 @@ # include // std::bit_cast # endif -// libc++ supports string_view in pre-c++17. -# if FMT_HAS_INCLUDE() && \ - (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# if defined(FMT_USE_STRING_VIEW) # include -# define FMT_USE_STRING_VIEW # endif # if FMT_MSC_VERSION @@ -744,12 +748,12 @@ template struct allocator : private std::decay { auto allocate(size_t n) -> T* { FMT_ASSERT(n <= max_value() / sizeof(T), ""); - T* p = static_cast(std::malloc(n * sizeof(T))); + T* p = static_cast(malloc(n * sizeof(T))); if (!p) FMT_THROW(std::bad_alloc()); return p; } - void deallocate(T* p, size_t) { std::free(p); } + void deallocate(T* p, size_t) { free(p); } constexpr friend auto operator==(allocator, allocator) noexcept -> bool { return true; // All instances of this allocator are equivalent. @@ -759,6 +763,14 @@ template struct allocator : private std::decay { } }; +template +FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) + -> decltype(f.set_debug_format(set)) { + f.set_debug_format(set); +} +template +FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} + } // namespace detail FMT_BEGIN_EXPORT @@ -2506,7 +2518,7 @@ FMT_CONSTEXPR20 auto write_fixed(OutputIt out, const DecimalFP& f, auto grouping = Grouping(loc, specs.localized()); size += grouping.count_separators(exp); return write_padded( - out, specs, to_unsigned(size), [&](iterator it) { + out, specs, static_cast(size), [&](iterator it) { if (s != sign::none) *it++ = detail::getsign(s); it = write_significand(it, f.significand, significand_size, f.exponent, grouping); diff --git a/include/spdlog/fmt/bundled/os.h b/include/spdlog/fmt/bundled/os.h index 40cdcdd4..94d730de 100644 --- a/include/spdlog/fmt/bundled/os.h +++ b/include/spdlog/fmt/bundled/os.h @@ -136,10 +136,9 @@ FMT_API std::system_error vwindows_error(int error_code, string_view fmt, * **Example**: * * // This throws a system_error with the description - * // cannot open file 'madeup': The system cannot find the file - * specified. - * // or similar (system message may vary). - * const char *filename = "madeup"; + * // cannot open file 'foo': The system cannot find the file specified. + * // or similar (system message may vary) if the file doesn't exist. + * const char *filename = "foo"; * LPOFSTRUCT of = LPOFSTRUCT(); * HFILE file = OpenFile(filename, &of, OF_READ); * if (file == HFILE_ERROR) { @@ -365,17 +364,17 @@ FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size(); /// A fast buffered output stream for writing from a single thread. Writing from /// multiple threads without external synchronization may result in a data race. -class FMT_API ostream : private detail::buffer { +class ostream : private detail::buffer { private: file file_; - ostream(cstring_view path, const detail::ostream_params& params); + FMT_API ostream(cstring_view path, const detail::ostream_params& params); - static void grow(buffer& buf, size_t); + FMT_API static void grow(buffer& buf, size_t); public: - ostream(ostream&& other) noexcept; - ~ostream(); + FMT_API ostream(ostream&& other) noexcept; + FMT_API ~ostream(); operator writer() { detail::buffer& buf = *this; diff --git a/include/spdlog/fmt/bundled/ranges.h b/include/spdlog/fmt/bundled/ranges.h index 24c61e93..36b38e29 100644 --- a/include/spdlog/fmt/bundled/ranges.h +++ b/include/spdlog/fmt/bundled/ranges.h @@ -18,6 +18,13 @@ #include "format.h" +#if FMT_HAS_CPP_ATTRIBUTE(clang::lifetimebound) +# define FMT_LIFETIMEBOUND [[clang::lifetimebound]] +#else +# define FMT_LIFETIMEBOUND +#endif +FMT_PRAGMA_CLANG(diagnostic error "-Wreturn-stack-address") + FMT_BEGIN_NAMESPACE FMT_EXPORT @@ -234,14 +241,6 @@ using range_reference_type = template using uncvref_type = remove_cvref_t>; -template -FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) - -> decltype(f.set_debug_format(set)) { - f.set_debug_format(set); -} -template -FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} - template struct range_format_kind_ : std::integral_constant{1, 'a'}; + * auto t = std::tuple(1, 'a'); * fmt::print("{}", fmt::join(t, ", ")); * // Output: 1, a */ template ::value)> -FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep) +FMT_CONSTEXPR auto join(const Tuple& tuple FMT_LIFETIMEBOUND, string_view sep) -> tuple_join_view { return {tuple, sep}; } diff --git a/include/spdlog/fmt/bundled/std.h b/include/spdlog/fmt/bundled/std.h index 5cf10618..184c6d26 100644 --- a/include/spdlog/fmt/bundled/std.h +++ b/include/spdlog/fmt/bundled/std.h @@ -111,12 +111,17 @@ void write_escaped_path(basic_memory_buffer& quoted, #endif // FMT_CPP_LIB_FILESYSTEM #if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT -template -auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { + +template +auto write_escaped_alternative(OutputIt out, const T& v, FormatContext& ctx) + -> OutputIt { if constexpr (has_to_string_view::value) return write_escaped_string(out, detail::to_string_view(v)); if constexpr (std::is_same_v) return write_escaped_char(out, v); - return write(out, v); + + formatter, Char> underlying; + maybe_set_debug_format(underlying, true); + return underlying.format(v, ctx); } #endif @@ -139,50 +144,39 @@ template class is_variant_formattable { #endif // FMT_CPP_LIB_VARIANT #if FMT_USE_RTTI - -template -auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { -# ifdef FMT_HAS_ABI_CXA_DEMANGLE - int status = 0; - size_t size = 0; - std::unique_ptr demangled_name_ptr( - abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); - - string_view demangled_name_view; - if (demangled_name_ptr) { - demangled_name_view = demangled_name_ptr.get(); - - // Normalization of stdlib inline namespace names. - // libc++ inline namespaces. - // std::__1::* -> std::* - // std::__1::__fs::* -> std::* - // libstdc++ inline namespaces. - // std::__cxx11::* -> std::* - // std::filesystem::__cxx11::* -> std::filesystem::* - if (demangled_name_view.starts_with("std::")) { - char* begin = demangled_name_ptr.get(); - char* to = begin + 5; // std:: - for (char *from = to, *end = begin + demangled_name_view.size(); - from < end;) { - // This is safe, because demangled_name is NUL-terminated. - if (from[0] == '_' && from[1] == '_') { - char* next = from + 1; - while (next < end && *next != ':') next++; - if (next[0] == ':' && next[1] == ':') { - from = next + 2; - continue; - } +inline auto normalize_libcxx_inline_namespaces(string_view demangled_name_view, + char* begin) -> string_view { + // Normalization of stdlib inline namespace names. + // libc++ inline namespaces. + // std::__1::* -> std::* + // std::__1::__fs::* -> std::* + // libstdc++ inline namespaces. + // std::__cxx11::* -> std::* + // std::filesystem::__cxx11::* -> std::filesystem::* + if (demangled_name_view.starts_with("std::")) { + char* to = begin + 5; // std:: + for (const char *from = to, *end = begin + demangled_name_view.size(); + from < end;) { + // This is safe, because demangled_name is NUL-terminated. + if (from[0] == '_' && from[1] == '_') { + const char* next = from + 1; + while (next < end && *next != ':') next++; + if (next[0] == ':' && next[1] == ':') { + from = next + 2; + continue; } - *to++ = *from++; } - demangled_name_view = {begin, detail::to_unsigned(to - begin)}; + *to++ = *from++; } - } else { - demangled_name_view = string_view(ti.name()); + demangled_name_view = {begin, detail::to_unsigned(to - begin)}; } - return detail::write_bytes(out, demangled_name_view); -# elif FMT_MSC_VERSION - const string_view demangled_name(ti.name()); + return demangled_name_view; +} + +template +auto normalize_msvc_abi_name(string_view abi_name_view, OutputIt out) + -> OutputIt { + const string_view demangled_name(abi_name_view); for (size_t i = 0; i < demangled_name.size(); ++i) { auto sub = demangled_name; sub.remove_prefix(i); @@ -201,6 +195,39 @@ auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { if (*sub.begin() != ' ') *out++ = *sub.begin(); } return out; +} + +template +auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { +# ifdef FMT_HAS_ABI_CXA_DEMANGLE + int status = 0; + size_t size = 0; + std::unique_ptr demangled_name_ptr( + abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &free); + + string_view demangled_name_view; + if (demangled_name_ptr) { + demangled_name_view = normalize_libcxx_inline_namespaces( + demangled_name_ptr.get(), demangled_name_ptr.get()); + } else { + demangled_name_view = string_view(ti.name()); + } + return detail::write_bytes(out, demangled_name_view); +# elif FMT_MSC_VERSION && defined(_MSVC_STL_UPDATE) + return normalize_msvc_abi_name(ti.name(), out); +# elif FMT_MSC_VERSION && defined(_LIBCPP_VERSION) + const string_view demangled_name = ti.name(); + std::string name_copy(demangled_name.size(), '\0'); + // normalize_msvc_abi_name removes class, struct, union etc that MSVC has in + // front of types + name_copy.erase(normalize_msvc_abi_name(demangled_name, name_copy.begin()), + name_copy.end()); + // normalize_libcxx_inline_namespaces removes the inline __1, __2, etc + // namespaces libc++ uses for ABI versioning On MSVC ABI + libc++ + // environments, we need to eliminate both of them. + const string_view normalized_name = + normalize_libcxx_inline_namespaces(name_copy, name_copy.data()); + return detail::write_bytes(out, normalized_name); # else return detail::write_bytes(out, string_view(ti.name())); # endif @@ -255,21 +282,6 @@ template auto ptr(const std::shared_ptr& p) -> const void* { #if FMT_CPP_LIB_FILESYSTEM -class path : public std::filesystem::path { - public: - auto display_string() const -> std::string { - const std::filesystem::path& base = *this; - return fmt::format(FMT_STRING("{}"), base); - } - auto system_string() const -> std::string { return string(); } - - auto generic_display_string() const -> std::string { - const std::filesystem::path& base = *this; - return fmt::format(FMT_STRING("{:g}"), base); - } - auto generic_system_string() const -> std::string { return generic_string(); } -}; - template struct formatter { private: format_specs specs_; @@ -319,6 +331,21 @@ template struct formatter { } }; +class path : public std::filesystem::path { + public: + auto display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{}"), base); + } + auto system_string() const -> std::string { return string(); } + + auto generic_display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{:g}"), base); + } + auto generic_system_string() const -> std::string { return generic_string(); } +}; + #endif // FMT_CPP_LIB_FILESYSTEM template @@ -353,25 +380,16 @@ template struct formatter, Char, std::enable_if_t::value>> { private: - formatter underlying_; + formatter, Char> underlying_; static constexpr basic_string_view optional = detail::string_literal{}; static constexpr basic_string_view none = detail::string_literal{}; - template - FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) - -> decltype(u.set_debug_format(set)) { - u.set_debug_format(set); - } - - template - FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} - public: FMT_CONSTEXPR auto parse(parse_context& ctx) { - maybe_set_debug_format(underlying_, true); + detail::maybe_set_debug_format(underlying_, true); return underlying_.parse(ctx); } @@ -407,10 +425,10 @@ struct formatter, Char, if (value.has_value()) { out = detail::write(out, "expected("); if constexpr (!std::is_void::value) - out = detail::write_escaped_alternative(out, *value); + out = detail::write_escaped_alternative(out, *value, ctx); } else { out = detail::write(out, "unexpected("); - out = detail::write_escaped_alternative(out, value.error()); + out = detail::write_escaped_alternative(out, value.error(), ctx); } *out++ = ')'; return out; @@ -474,7 +492,7 @@ struct formatter(out, v); + out = detail::write_escaped_alternative(out, v, ctx); }, value); } @@ -495,6 +513,8 @@ template <> struct formatter { bool debug_ = false; public: + FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } + FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { auto it = ctx.begin(), end = ctx.end(); if (it == end) return it; diff --git a/src/bundled_fmtlib_format.cpp b/src/bundled_fmtlib_format.cpp index 999d6428..8ec479cb 100644 --- a/src/bundled_fmtlib_format.cpp +++ b/src/bundled_fmtlib_format.cpp @@ -13,18 +13,21 @@ FMT_BEGIN_NAMESPACE #if FMT_USE_LOCALE -template FMT_API locale_ref::locale_ref(const std::locale& loc); +template FMT_API locale_ref::locale_ref(const std::locale& loc); // DEPRECATED! template FMT_API auto locale_ref::get() const -> std::locale; #endif namespace detail { -template FMT_API auto dragonbox::to_decimal(float x) noexcept -> dragonbox::decimal_fp; -template FMT_API auto dragonbox::to_decimal(double x) noexcept -> dragonbox::decimal_fp; +template FMT_API auto dragonbox::to_decimal(float x) noexcept + -> dragonbox::decimal_fp; +template FMT_API auto dragonbox::to_decimal(double x) noexcept + -> dragonbox::decimal_fp; // Explicit instantiations for char. -template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result; +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; template FMT_API auto decimal_point_impl(locale_ref) -> char; // DEPRECATED! @@ -32,7 +35,8 @@ template FMT_API void buffer::append(const char*, const char*); // Explicit instantiations for wchar_t. -template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result; +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; // DEPRECATED!