Skip to content

Commit 37e6474

Browse files
authored
Fix dynamic named arg format spec handling (#4361)
When dealing with dynamic named format args, need to account for nested named args when skipping the content of the replacement. Fixes #4360
1 parent 77c0fc0 commit 37e6474

File tree

2 files changed

+15
-1
lines changed

2 files changed

+15
-1
lines changed

include/fmt/base.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,19 @@ class format_string_checker {
17181718
-> const Char* {
17191719
context_.advance_to(begin);
17201720
if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
1721-
while (begin != end && *begin != '}') ++begin;
1721+
1722+
// If id is out of range, it means we do not know the type and cannot parse
1723+
// the format at compile time. Instead, skip over content until we finish
1724+
// the format spec, accounting for any nested replacements.
1725+
auto bracket_count = 0;
1726+
while (begin != end && (bracket_count > 0 || *begin != '}')) {
1727+
if (*begin == '{')
1728+
++bracket_count;
1729+
else if (*begin == '}')
1730+
--bracket_count;
1731+
1732+
++begin;
1733+
}
17221734
return begin;
17231735
}
17241736

test/format-test.cc

+2
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ TEST(format_test, named_arg) {
582582
EXPECT_EQ("1/a/A", fmt::format("{_1}/{a_}/{A_}", fmt::arg("a_", 'a'),
583583
fmt::arg("A_", "A"), fmt::arg("_1", 1)));
584584
EXPECT_EQ(fmt::format("{0:{width}}", -42, fmt::arg("width", 4)), " -42");
585+
EXPECT_EQ(fmt::format("{value:{width}}", fmt::arg("value", -42),
586+
fmt::arg("width", 4)), " -42");
585587
EXPECT_EQ("st",
586588
fmt::format("{0:.{precision}}", "str", fmt::arg("precision", 2)));
587589
EXPECT_EQ(fmt::format("{} {two}", 1, fmt::arg("two", 2)), "1 2");

0 commit comments

Comments
 (0)