Build format-test.cc with FMT_USE_LOCALE=0 in nolocale-test instead of a
separate test file. This replaces two ad-hoc checks with the whole format
test suite. The locale-dependent tests were guarded by the removed
FMT_STATIC_THOUSANDS_SEPARATOR macro, so the guard never took effect.
Since GCC 16, in Debug (meaning `-O0`) builds,
`-Wmaybe-uninitialized` falsely warns in certain situations where
you convert a pointer to a not-yet-initialized variable to pointer-to-const.
Associated bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127470
Format an enum as its underlying value if the enum is annotated with
fmt::as_underlying, the equivalent of std::format_as_underlying from P4267:
enum class [[=fmt::as_underlying]] color { red = 1, green = 2, blue = 4 };
fmt::format("{:04x}", color::blue); // "0004"
The value is mapped before type erasure via the existing
formatter<T>::format_as hook, as in the std::byte formatter, so it is stored
as a builtin argument and can be used as dynamic width or precision.
Combining the annotation with fmt::as_identifiers is rejected with a
static_assert.
%.0i and %.0u take the same path as %.0d because 'i' and 'u' are normalized
to 'd', the uppercase variants only set the upper flag which is unobservable
when there are no digits, and %-5.0d cannot be distinguished from %5.0d
because the output is empty.
Reuse getsign instead of mapping the sign to a string and let write_bytes'
default_align handle align::none. Also drop the presentation type check:
printf only produces dec, oct and hex for a non-char integral argument
because 'c' converts the argument to the char type.
The tuple formatter had a bespoke trait to keep format_as from producing an
ambiguous specialization. detail::has_format_as already answers that question
and std.h applies it the same way, so move it from std.h to format.h where
ranges.h can see it and drop the extra trait.
Check it with conditional_t rather than &&: is_tuple_formattable must not be
instantiated for types with format_as because for self-referential tuple-like
types that recurses back into formatter selection, and && short-circuits
evaluation but not instantiation.
format.h and std.h suppress Clang warnings for declarations provided by
fmt, but do not restore the previous diagnostic state. Including either
header therefore also hides the corresponding warning in unrelated
consumer code.
Use fmt's existing Clang diagnostic push and pop macros to limit
-Wweak-vtables to format_error and -Wbit-int-extension to the two
_BitInt aliases.
Signed-off-by: Yongqiang Tian <yqtian668@gmail.com>
Both specializations are always parsed while only the selected one is
instantiated. The #else branch it replaces is compiled by no target:
nolocale-test builds src/format.cc, which never reaches chrono.h.
tm_writer takes a locale_ref and the localized flag instead of a std::locale
reference, and resolves the locale the same way numeric {:L} does: classic
unless localized, otherwise the one passed to the formatting function or the
global one. The facet calls are confined to three shims, so with locale
support disabled nothing pulls in std::locale. get_locale, which existed only
to materialize and own a std::locale, is no longer needed.
The std::tm formatter treated a missing locale argument as the classic locale
rather than the global one, and since #4935 routes {:L} on weekday and month
through it, {:L} without a locale argument ignored the global locale for all
calendar types. It now uses the global locale, as numeric {:L} does. Output
with an explicit locale is unchanged. With FMT_USE_LOCALE=0, {:L} no longer
consults the global locale, matching numeric formatting under that option. An
-Os test program loses all 16 of its std::locale and time_put symbols.
formatter<year_month_day>::format passes true to get_locale, so every default
format constructs a std::locale, and tm_writer then compares it against the
classic locale (is_classic_(loc_ == get_classic_locale())). The only thing
written is on_iso_date(), which is pure arithmetic and reads neither loc_ nor
is_classic_.
It is the odd one out among its siblings: formatter<day> and formatter<year>
pass false; formatter<weekday> and formatter<month> pass their localized()
flag. Only year_month_day hardcodes true, and its parse() never sets localized
in the first place.
With FMT_USE_LOCALE=0 this costs more than a copy: the loc.get<std::locale>()
arm of get_locale is compiled out, so it default-constructs instead, capturing
the current global locale in a build that asked for no locale support.
No output change: chrono_test.year_month_day already sets a non-classic global
locale and expects "2024-01-01".
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Don't let ADL pick to_string_view
02bf4d1c disabled ADL for to_string_view by qualifying the is_string trait,
and has_to_string_view and char_t are qualified for the same reason. Two call
sites were left behind: value's string constructor and the write() overload
for types with a string view conversion. Both sit inside fmt::detail, where an
unqualified call adds the argument's own namespace to the overload set.
That splits the two halves of one decision. Both call sites are reached only
through has_to_string_view or char_t, which are defined by the qualified
expression, so ADL can never be needed to satisfy them - it can only add
candidates the gate never considered. When the argument's namespace declares a
to_string_view template, the two tie during partial ordering and the call is
ambiguous:
core.h(2211): error C2668: 'to_string_view': ambiguous call to overloaded
function
note: could be 'string_view N::to_string_view<T>(const T&)' [found using
argument-dependent lookup]
note: or 'basic_string_view<char> fmt::detail::to_string_view<T,0>(const T&)'
Both are reachable. format("{}", x) stores the argument through value's
constructor; to_string(x) passes it to detail::write unmapped, which lands on
the write() overload, as do FMT_COMPILE named fields and
nested_formatter::write_arg. Reverting either line alone breaks the build of
the test that covers it.
This turned up in Microsoft Office, which declares a constrained
to_string_view template next to its own string types. It only breaks where
those types are distinct classes, so the same code compiles on platforms whose
string types are std aliases - the ADL set is namespace std there and picks up
nothing.
One behaviour change worth noting: a non-template to_string_view in the
argument's namespace used to win outright at these call sites, so a type that
satisfies is_std_string_like via find_first_of and data() but has no size()
formatted through ADL and now fails to compile, because the trait only checks
that the qualified overload is viable, not that its body instantiates. That is
the removed extension point going away rather than a new restriction; ADL
to_string_view stopped being supported in 02bf4d1c.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nolocale-test defines FMT_STATIC_THOUSANDS_SEPARATOR, which stopped doing
anything in b90b4bc9 ("Remove FMT_STATIC_THOUSANDS_SEPARATOR in favor of
FMT_USE_LOCALE"). That macro no longer appears anywhere under include/, so
since then the target has compiled src/format.cc with locale support enabled.
It is not a dead target: the pedantic CI jobs build it (linux.yml, macos.yml
both pass -DFMT_PEDANTIC=ON), and it passes. So the configuration looks
covered while nothing actually tests it. #4627 - a locale-off build break -
landed during that window.
Define FMT_USE_LOCALE=0 instead.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nolocale-test compiles src/format.cc directly, so it does not pick up the
/utf-8 that CMakeLists.txt adds to the fmt target. On MSVC the static_assert
in base.h then fires: "Unicode support requires compiling with /utf-8".
The target only exists under FMT_PEDANTIC, which the Windows workflow does not
set, so this has not shown up in CI. unicode-test already guards the same flag
the same way.
One of its unique features is that it serializes the format
string and all format arguments to the thread's SPSQ queue
to minimize processing on hotpath and then deserializes them
on the backend thread which performs formatting using {fmt}
and writing to the log sinks.
Signed-off-by: Alexander Lobakin <alobakin@mailbox.org>
The '0' modifier was documented in ca8eeb09 (#3976) and the parser case for
it was removed nine days later in 7bd11b5c ("Remove a redundant extension to
reduce divergence from std::format"), which did not update the docs. Since
then the grammar and the modifier table have promised a modifier that
parse_chrono_format rejects with "invalid format", for all 11 of the
presentation types the same section lists as supporting it.
Zero padding remains the default, so the extension really was redundant;
this only aligns the documentation with the code.
Co-authored-by: Dylan Pulver <dylanpulver@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>