Compare commits

...

5 Commits

Author SHA1 Message Date
Martin Storsjö
758d39eb23
Add a missing include for the C++ module build (#4868)
The std.h header uses types such as std::atomic and std::atomic_flag.
For the normal build mode, this header does include all the
headers it needs, such as <atomic>.

However when building the C++ module of {fmt}, the std.h header
omits such includes, and instead expects them to be included
beforehand by fmt.cc - which lacked including <atomic>.

This fixes building the C++ module with libc++ 23, which has removed
a number of unnecessary transitive includes.
2026-07-29 12:23:12 -07:00
Aaron Gokaslan
c0330b7466
Do not optin into CPP modules without SCAN_DEPS on Clang (#4867) 2026-07-29 11:08:57 -07:00
Victor Zverovich
a00f82c6b6 Bump version 2026-07-29 11:04:35 -07:00
rimathia
17500e457b
doc extension concerning format_as and general implementations (#4857) 2026-07-29 09:43:31 -07:00
Victor Zverovich
26c01df3bd Handle const-qualified named arguments
A named argument that arrives const-qualified was not recognized by
is_named_arg, silently dropping its name. This happens both when a
named argument is passed through an intermediate function returning
const T& (https://github.com/fmtlib/fmt/issues/4866) and in fmt's own
compiled format path, which passes arguments as const T&.

Make is_named_arg and is_static_named_arg see through top-level const so
the name is preserved instead of dropped.
2026-07-29 09:20:23 -07:00
6 changed files with 26 additions and 7 deletions

View File

@ -13,6 +13,10 @@ jobs:
${{matrix.shared && 'Shared' || ''}} ${{matrix.shared && 'Shared' || ''}}
${{matrix.cxxflags_extra && 'Sanitize' || ''}} ${{matrix.cxxflags_extra && 'Sanitize' || ''}}
runs-on: ${{ matrix.os || 'ubuntu-22.04' }} runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
env:
# Run tests in a non-UTC timezone. glibc localtime/strftime honor TZ, so
# there is no need for timedatectl, which fails without systemd-timedated.
TZ: Europe/Kyiv
strategy: strategy:
matrix: matrix:
cxx: [g++-4.9, g++-11, clang++-3.6, clang++-11] cxx: [g++-4.9, g++-11, clang++-3.6, clang++-11]
@ -75,15 +79,14 @@ jobs:
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set timezone
run: sudo timedatectl set-timezone 'Europe/Kyiv'
- name: Install GCC 4.9 - name: Install GCC 4.9
run: | run: |
sudo apt update sudo apt update
sudo apt install libatomic1 libc6-dev libgomp1 libitm1 libmpc3 sudo apt install libatomic1 libc6-dev libgomp1 libitm1 libmpc3
# https://launchpad.net/ubuntu/xenial/amd64/g++-4.9/4.9.3-13ubuntu2 # https://launchpad.net/ubuntu/xenial/amd64/g++-4.9/4.9.3-13ubuntu2
wget --no-verbose \ # launchpad periodically returns 503s, so retry to avoid flaky CI.
wget --no-verbose --tries=5 --waitretry=10 \
--retry-connrefused --retry-on-http-error=503 \
http://launchpadlibrarian.net/230069137/libmpfr4_3.1.3-2_amd64.deb \ http://launchpadlibrarian.net/230069137/libmpfr4_3.1.3-2_amd64.deb \
http://launchpadlibrarian.net/253728424/libasan1_4.9.3-13ubuntu2_amd64.deb \ http://launchpadlibrarian.net/253728424/libasan1_4.9.3-13ubuntu2_amd64.deb \
http://launchpadlibrarian.net/445346135/libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \ http://launchpadlibrarian.net/445346135/libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
@ -114,7 +117,9 @@ jobs:
sudo apt update sudo apt update
sudo apt install libtinfo5 sudo apt install libtinfo5
# https://code.launchpad.net/ubuntu/xenial/amd64/clang-3.6/1:3.6.2-3ubuntu2 # https://code.launchpad.net/ubuntu/xenial/amd64/clang-3.6/1:3.6.2-3ubuntu2
wget --no-verbose \ # launchpad periodically returns 503s, so retry to avoid flaky CI.
wget --no-verbose --tries=5 --waitretry=10 \
--retry-connrefused --retry-on-http-error=503 \
http://launchpadlibrarian.net/230019046/libffi6_3.2.1-4_amd64.deb \ http://launchpadlibrarian.net/230019046/libffi6_3.2.1-4_amd64.deb \
http://launchpadlibrarian.net/445346109/libasan2_5.4.0-6ubuntu1~16.04.12_amd64.deb \ http://launchpadlibrarian.net/445346109/libasan2_5.4.0-6ubuntu1~16.04.12_amd64.deb \
http://launchpadlibrarian.net/445346135/libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \ http://launchpadlibrarian.net/445346135/libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \

View File

@ -65,7 +65,8 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.28 AND CMAKE_CXX_STANDARD
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION
GREATER_EQUAL 15) GREATER_EQUAL 15)
OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 16) AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 16
AND CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS)
OR (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION OR (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION
GREATER_EQUAL 1934)) GREATER_EQUAL 1934))
set(FMT_USE_CMAKE_MODULES TRUE) set(FMT_USE_CMAKE_MODULES TRUE)

View File

@ -92,6 +92,10 @@ Use `format_as` if you want to make your type formattable as some other
type with the same format specifiers. The `format_as` function should type with the same format specifiers. The `format_as` function should
take an object of your type and return an object of a formattable type. take an object of your type and return an object of a formattable type.
It should be defined in the same namespace as your type. It should be defined in the same namespace as your type.
`format_as` cannot be used when a type also matches another `formatter`
specialization, such as the range `formatter`, because the specializations
would be ambiguous. Disable the conflicting specialization, if possible,
or provide an explicit `formatter` specialization instead.
Example ([run](https://godbolt.org/z/nvME4arz8)): Example ([run](https://godbolt.org/z/nvME4arz8)):

View File

@ -21,7 +21,7 @@
#endif #endif
// The fmt library version in the form major * 10000 + minor * 100 + patch. // The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 120200 #define FMT_VERSION 120201
// Detect compiler versions. // Detect compiler versions.
#if defined(__clang__) && !defined(__ibmxl__) #if defined(__clang__) && !defined(__ibmxl__)
@ -1059,6 +1059,10 @@ template <typename T> struct is_static_named_arg : std::false_type {};
template <typename T, typename Char> template <typename T, typename Char>
struct is_named_arg<named_arg<T, Char>> : std::true_type {}; struct is_named_arg<named_arg<T, Char>> : std::true_type {};
template <typename T> struct is_named_arg<const T> : is_named_arg<T> {};
template <typename T>
struct is_static_named_arg<const T> : is_static_named_arg<T> {};
template <typename T, typename Char = char> struct named_arg : view { template <typename T, typename Char = char> struct named_arg : view {
const Char* name; const Char* name;
const T& value; const T& value;

View File

@ -19,6 +19,7 @@ module;
// to prevent attachment to this module. // to prevent attachment to this module.
#ifndef FMT_IMPORT_STD #ifndef FMT_IMPORT_STD
# include <algorithm> # include <algorithm>
# include <atomic>
# include <bitset> # include <bitset>
# include <chrono> # include <chrono>
# include <cmath> # include <cmath>

View File

@ -163,6 +163,10 @@ TEST(compile_test, named) {
fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43)); fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43));
EXPECT_EQ("41 43", EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41)); fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41));
// A statically-named argument with a format spec compiles to spec_field,
// which passes the argument to make_format_args as const (#4866).
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{arg:3.1f}"), "arg"_a = 4.2));
# endif # endif
} }