From a1826a2785df741293efdc93f1f269cd7f234a80 Mon Sep 17 00:00:00 2001 From: Nerixyz Date: Tue, 26 May 2026 20:35:36 +0200 Subject: [PATCH 1/4] [Docs] Show formatv provider options in programmers manual --- llvm/docs/ProgrammersManual.rst | 201 +++++++++++++++++- llvm/include/llvm/Support/FormatProviders.h | 4 +- llvm/unittests/Support/FormatVariadicTest.cpp | 47 ++++ 3 files changed, 249 insertions(+), 3 deletions(-) diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst index ce786a5b7b681..f95918bbd7d74 100644 --- a/llvm/docs/ProgrammersManual.rst +++ b/llvm/docs/ProgrammersManual.rst @@ -314,7 +314,7 @@ or ``+`` (right align). The default is right aligned. ``style`` is an optional string consisting of a type specific that controls the formatting of the value. For example, to format a floating point value as a percentage, -you can use the style option ``P``. +you can use the style option ``P``. See :ref:`formatv_provider_options` for common options. Custom formatting ^^^^^^^^^^^^^^^^^ @@ -404,6 +404,205 @@ doxygen documentation or by looking at the unit test suite. S = formatv("{0:$[+]}", make_range(V.begin(), V.end())); // S == "8+9+10" S = formatv("{0:$[ + ]@[x]}", make_range(V.begin(), V.end())); // S == "0x8 + 0x9 + 0xA" +.. _formatv_provider_options: + +Format provider options +^^^^^^^^^^^^^^^^^^^^^^^ + +- **Integers**: The options string of an integral type has the grammar: :: + + integer_options :: [style][digits] + style :: + digits :: 0-99 + + +-----------------+-----------------------+----------------------+--------------------+ + | ``style`` | Meaning | Example | ``digits`` Meaning | + +-----------------+-----------------------+--------+-------------+--------------------+ + | | | Input | Output | | + +=================+=======================+========+=============+====================+ + | ``x-`` | Hex no prefix, lower | 42 | ``2a`` | Minimum # digits | + +-----------------+-----------------------+--------+-------------+--------------------+ + | ``X-`` | Hex no prefix, upper | 42 | ``2A`` | Minimum # digits | + +-----------------+-----------------------+--------+-------------+--------------------+ + | ``x+`` / ``x`` | Hex + prefix, lower | 42 | ``0x2a`` | Minimum # digits | + +-----------------+-----------------------+--------+-------------+--------------------+ + | ``X+`` / ``X`` | Hex + prefix, upper | 42 | ``0x2A`` | Minimum # digits | + +-----------------+-----------------------+--------+-------------+--------------------+ + | ``N`` / ``n`` | Digit grouped number | 123456 | ``123,456`` | Ignored | + +-----------------+-----------------------+--------+-------------+--------------------+ + | ``D`` / ``d`` | Integer | 100000 | ``100000`` | Ignored | + +-----------------+-----------------------+--------+-------------+--------------------+ + |``+D`` / ``+d`` | Integer with + prefix | 100000 | ``+100000`` | Ignored | + | | for numbers ``>= 0`` | | | | + +-----------------+-----------------------+--------+-------------+--------------------+ + | ``+`` | Same as ``+D``/``+d`` | | | | + +-----------------+-----------------------+--------+-------------+--------------------+ + | (empty) | Same as ``D``/``d`` | | | | + +-----------------+-----------------------+--------+-------------+--------------------+ + + .. Keep in sync with FormatVariadicTest.DocsInt + + .. code-block:: c++ + + std::string S; + int I = 1234567; + S = formatv("{0}", I); // S == "1234567"; + S = formatv("{0:8}", I); // S == "01234567"; + S = formatv("{0:x}", I); // S == "0x12d687"; + S = formatv("{0:x8}", I); // S == "0x0012d687"; + S = formatv("{0:n}", I); // S == "1,234,567"; + S = formatv("{0:+d}", I); // S == "+1234567"; + S = formatv("{0:+d}", -I); // S == "-1234567"; + +- **Pointers**: The options string of a pointer type has the grammar: :: + + pointer_options :: [style][precision] + style :: + digits :: 0-sizeof(void*) + + +-----------------+--------------------------+---------------------------------+ + | ``style`` | Meaning | Example | + +-----------------+--------------------------+----------------+----------------+ + | | | Input | Output | + +=================+==========================+================+================+ + | ``x-`` | Hex no prefix, lower | ``0xDEADBEEF`` | ``deadbeef`` | + +-----------------+--------------------------+----------------+----------------+ + | ``X-`` | Hex no prefix, upper | ``0xDEADBEEF`` | ``2ADEADBEEF`` | + +-----------------+--------------------------+----------------+----------------+ + | ``x+`` / ``x`` | Hex + prefix, lower | ``0xDEADBEEF`` | ``0xdeadbeef`` | + +-----------------+--------------------------+----------------+----------------+ + | ``X+`` / ``X`` | Hex + prefix, upper | ``0xDEADBEEF`` | ``0xDEADBEEF`` | + +-----------------+--------------------------+----------------+----------------+ + | (empty) | Same as ``X+`` / ``X`` | | | + +-----------------+--------------------------+----------------+----------------+ + + The default precision is the number of nibbles in a machine word, and in all + cases indicates the minimum number of nibbles to print. + + .. Keep in sync with FormatVariadicTest.DocsPointer + + .. code-block:: c++ + + std::string S; + void *P = (void*)0xABCD12; + S = formatv("{0}", P); // S == "0x0000000000ABCD12"; (sizeof(void*) == 8) + S = formatv("{0:8}", P); // S == "0x00ABCD12"; + S = formatv("{0:x8}", P); // S == "0x00abcd12"; + +- **Strings**: This applies to C-style strings and string objects such as + ``std::string`` or ``llvm::StringRef``. The options string of a string type + has the grammar: :: + + string_options :: [length] + + where ``length`` is an optional integer specifying the maximum number of + characters in the string to print. If ``length`` is omitted, the string is + printed up to the null terminator. + + .. Keep in sync with FormatVariadicTest.DocsStrings + + .. code-block:: c++ + + std::string S; + llvm::StringRef V = "A very long string"; + S = formatv("{0}", V); // S == "A very long string"; + S = formatv("{0:6}", V); // S == "A very"; + +- **Booleans**: The options string of a boolean type has the grammar: :: + + bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t" + + +---------------+---------------------+ + | Option | Meaning | + +===============+=====================+ + | ``Y`` | YES / NO | + +---------------+---------------------+ + | ``y`` | yes / no | + +---------------+---------------------+ + | ``D`` / ``d`` | Integer 0 or 1 | + +---------------+---------------------+ + | ``T`` | TRUE / FALSE | + +---------------+---------------------+ + | ``t`` | true / false | + +---------------+---------------------+ + | (empty) | Equivalent to ``t`` | + +---------------+---------------------+ + + .. Keep in sync with FormatVariadicTest.DocsBooleans + + .. code-block:: c++ + + std::string S; + S = formatv("{0}", true); // S == "true"; + S = formatv("{0:y}", false); // S == "no"; + +- **Floating point numbers**: The options string of a floating point type has + the grammar: :: + + float_options :: [style][precision] + style :: + precision :: 0-99 + + +---------------+------------------------+----------------------+ + | ``style`` | Meaning | Example | + +---------------+------------------------+--------+-------------+ + | | | Input | Output | + +===============+========================+========+=============+ + | ``P`` / ``p`` | Percentage | 0.05 | ``5.00%`` | + +---------------+------------------------+--------+-------------+ + | ``F`` / ``f`` | Fixed point | 1.0 | ``1.00`` | + +---------------+------------------------+--------+-------------+ + | ``E`` | Exponential with ``E`` | 100000 | ``1.0E+05`` | + +---------------+------------------------+--------+-------------+ + | ``e`` | Exponential with ``e`` | 100000 | ``1.0e+05`` | + +---------------+------------------------+--------+-------------+ + | (empty) | Same as ``F`` / ``f`` | | | + +---------------+------------------------+--------+-------------+ + + The default precision is 6 for exponential (``E`` / ``e``) and 2 for + everything else. + + .. Keep in sync with FormatVariadicTest.DocsFloats + + .. code-block:: c++ + + std::string S; + float F = 0.05f; + S = formatv("{0}", F); // S == "0.05"; + S = formatv("{0:e}", F); // S == "5.000000e-02"; + +- ``llvm::iterator_range``: This will print an arbitrary range as a delimited + sequence of items. The options string of a range type has the grammar: :: + + range_style ::= [separator][element_style] + separator ::= "$" delimeted_expr + element_style ::= "@" delimeted_expr + delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">" + expr ::= + + where the ``separator`` expression is the string to insert between consecutive + items in the range and the ``element_style`` expression is the style + specification to be used when formatting the underlying type. The default + separator if unspecified is ", ". The syntax of the argument expression + follows whatever grammar is dictated by the format provider or format adapter + used to format the value type. + + Note that attempting to format an ``iterator_range`` where no format + provider can be found for ``T`` will result in a compile error. + + .. Keep in sync with FormatVariadicTest.DocsIteratorRange + + .. code-block:: c++ + + std::string S; + std::vector V{1, 2, 4, 8, 16}; + S = formatv("{0}", iterator_range(V)); + // S == "1, 2, 4, 8, 16"; + S = formatv("{0:@(x)}", iterator_range(V)); + // S == "0x1, 0x2, 0x4, 0x8, 0x10"; + S = formatv("{0:$[,]@[2]}", iterator_range(V)); + // S == "01,02,04,08,16"; + .. _error_apis: Error handling diff --git a/llvm/include/llvm/Support/FormatProviders.h b/llvm/include/llvm/Support/FormatProviders.h index 78eeec76cf79b..6f416ac5e0c99 100644 --- a/llvm/include/llvm/Support/FormatProviders.h +++ b/llvm/include/llvm/Support/FormatProviders.h @@ -343,7 +343,7 @@ struct range_item_has_provider /// /// The options string of a range type has the grammar: /// -/// range_style ::= [separator] [element_style] +/// range_style ::= [separator][element_style] /// separator ::= "$" delimeted_expr /// element_style ::= "@" delimeted_expr /// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">" @@ -352,7 +352,7 @@ struct range_item_has_provider /// where the separator expression is the string to insert between consecutive /// items in the range and the argument expression is the Style specification to /// be used when formatting the underlying type. The default separator if -/// unspecified is ' ' (space). The syntax of the argument expression follows +/// unspecified is ", ". The syntax of the argument expression follows /// whatever grammar is dictated by the format provider or format adapter used /// to format the value type. /// diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp index ea549e7553b0c..1f33504d93499 100644 --- a/llvm/unittests/Support/FormatVariadicTest.cpp +++ b/llvm/unittests/Support/FormatVariadicTest.cpp @@ -903,6 +903,53 @@ TEST(FormatVariadicTest, Validate) { #endif // NDEBUG } +TEST(FormatVariadicTest, DocsInt) { + int I = 1234567; + EXPECT_EQ(formatv("{0}", I).str(), "1234567"); + EXPECT_EQ(formatv("{0:8}", I).str(), "01234567"); + EXPECT_EQ(formatv("{0:x}", I).str(), "0x12d687"); + EXPECT_EQ(formatv("{0:x8}", I).str(), "0x0012d687"); + EXPECT_EQ(formatv("{0:n}", I).str(), "1,234,567"); + EXPECT_EQ(formatv("{0:+d}", I).str(), "+1234567"); + EXPECT_EQ(formatv("{0:+d}", -I).str(), "-1234567"); +} + +TEST(FormatVariadicTest, DocsPointers) { + void *P = (void *)0xABCD12; + if constexpr (sizeof(void *) == 8) { + EXPECT_EQ(formatv("{0}", P).str(), "0x0000000000ABCD12"); + } else { + EXPECT_EQ(formatv("{0}", P).str(), "0x00ABCD12"); + } + EXPECT_EQ(formatv("{0:8}", P).str(), "0x00ABCD12"); + EXPECT_EQ(formatv("{0:x8}", P).str(), "0x00abcd12"); +} + +TEST(FormatVariadicTest, DocsStrings) { + llvm::StringRef V = "A very long string"; + EXPECT_EQ(formatv("{0}", V).str(), "A very long string"); + EXPECT_EQ(formatv("{0:6}", V).str(), "A very"); +} + +TEST(FormatVariadicTest, DocsBooleans) { + EXPECT_EQ(formatv("{0}", true).str(), "true"); + EXPECT_EQ(formatv("{0:y}", false).str(), "no"); +} + +TEST(FormatVariadicTest, DocsFloats) { + float F = 0.05f; + EXPECT_EQ(formatv("{0}", F).str(), "0.05"); + EXPECT_EQ(formatv("{0:e}", F).str(), "5.000000e-02"); +} + +TEST(FormatVariadicTest, DocsIteratorRange) { + std::vector V{1, 2, 4, 8, 16}; + EXPECT_EQ(formatv("{0}", iterator_range(V)).str(), "1, 2, 4, 8, 16"); + EXPECT_EQ(formatv("{0:@(x)}", iterator_range(V)).str(), + "0x1, 0x2, 0x4, 0x8, 0x10"); + EXPECT_EQ(formatv("{0:$[,]@[2]}", iterator_range(V)).str(), "01,02,04,08,16"); +} + namespace { enum class Base { First }; From 972bfb3f6ca81d6be1cc518fa90507ebc7d30e30 Mon Sep 17 00:00:00 2001 From: Nerixyz Date: Thu, 28 May 2026 10:09:02 +0200 Subject: [PATCH 2/4] Add example and test for `X-` --- llvm/docs/ProgrammersManual.rst | 3 +++ llvm/unittests/Support/FormatVariadicTest.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst index f95918bbd7d74..415b18440219f 100644 --- a/llvm/docs/ProgrammersManual.rst +++ b/llvm/docs/ProgrammersManual.rst @@ -450,6 +450,9 @@ Format provider options S = formatv("{0:8}", I); // S == "01234567"; S = formatv("{0:x}", I); // S == "0x12d687"; S = formatv("{0:x8}", I); // S == "0x0012d687"; + S = formatv("{0:x-}", I); // S == "12d687"; + S = formatv("{0:X-}", I); // S == "12D687"; + S = formatv("{0:x-8}", I); // S == "0012d687"; S = formatv("{0:n}", I); // S == "1,234,567"; S = formatv("{0:+d}", I); // S == "+1234567"; S = formatv("{0:+d}", -I); // S == "-1234567"; diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp index 1f33504d93499..d6c488f009d0d 100644 --- a/llvm/unittests/Support/FormatVariadicTest.cpp +++ b/llvm/unittests/Support/FormatVariadicTest.cpp @@ -909,6 +909,9 @@ TEST(FormatVariadicTest, DocsInt) { EXPECT_EQ(formatv("{0:8}", I).str(), "01234567"); EXPECT_EQ(formatv("{0:x}", I).str(), "0x12d687"); EXPECT_EQ(formatv("{0:x8}", I).str(), "0x0012d687"); + EXPECT_EQ(formatv("{0:x-}", I).str(), "12d687"); + EXPECT_EQ(formatv("{0:X-}", I).str(), "12D687"); + EXPECT_EQ(formatv("{0:x-8}", I).str(), "0012d687"); EXPECT_EQ(formatv("{0:n}", I).str(), "1,234,567"); EXPECT_EQ(formatv("{0:+d}", I).str(), "+1234567"); EXPECT_EQ(formatv("{0:+d}", -I).str(), "-1234567"); From 097626afcd4336c58202b7a421631f56f3cdbc65 Mon Sep 17 00:00:00 2001 From: Nerixyz Date: Thu, 28 May 2026 10:09:35 +0200 Subject: [PATCH 3/4] Capitalize `W` --- llvm/docs/ProgrammersManual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst index 415b18440219f..f13290e619ad1 100644 --- a/llvm/docs/ProgrammersManual.rst +++ b/llvm/docs/ProgrammersManual.rst @@ -498,7 +498,7 @@ Format provider options string_options :: [length] - where ``length`` is an optional integer specifying the maximum number of + Where ``length`` is an optional integer specifying the maximum number of characters in the string to print. If ``length`` is omitted, the string is printed up to the null terminator. @@ -583,7 +583,7 @@ Format provider options delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">" expr ::= - where the ``separator`` expression is the string to insert between consecutive + Where the ``separator`` expression is the string to insert between consecutive items in the range and the ``element_style`` expression is the style specification to be used when formatting the underlying type. The default separator if unspecified is ", ". The syntax of the argument expression From 1c9d93e53801cb8f66bce95e6e9ef90ca385298b Mon Sep 17 00:00:00 2001 From: Nerixyz Date: Thu, 28 May 2026 10:12:56 +0200 Subject: [PATCH 4/4] Reword precision on pointers --- llvm/docs/ProgrammersManual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst index f13290e619ad1..2a38bf07b06d3 100644 --- a/llvm/docs/ProgrammersManual.rst +++ b/llvm/docs/ProgrammersManual.rst @@ -480,7 +480,7 @@ Format provider options +-----------------+--------------------------+----------------+----------------+ The default precision is the number of nibbles in a machine word, and in all - cases indicates the minimum number of nibbles to print. + cases the precision indicates the minimum number of nibbles to print. .. Keep in sync with FormatVariadicTest.DocsPointer