Skip to content

Commit a9e5773

Browse files
committed
[libc++][format] Implements formatting pointer.
The feature is applied as DR instead of a normal paper. MSVC STL and libstdc++ will do the same. Implements - P2510R3 Formatting pointers Depends on D153192 Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D153195
1 parent 1403080 commit a9e5773

File tree

14 files changed

+56
-25
lines changed

14 files changed

+56
-25
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Implemented Papers
4747
- P2505R5 - Monadic operations for ``std::expected``
4848
- P2711R1 - Making Multi-Param Constructors Of views explicit (``join_with_view`` is not done yet)
4949
- P2572R1 - ``std::format`` fill character allowances
50+
- P2510R3 - Formatting pointers
5051

5152
Improvements and New Features
5253
-----------------------------

libcxx/docs/Status/Cxx2c.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Paper Status
3737
:header-rows: 1
3838
:widths: auto
3939

40+
.. note::
41+
42+
.. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
43+
4044
.. _issues-status-cxx2c:
4145

4246
Library Working Group Issues Status

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"`P2530R3 <https://wg21.link/P2530R3>`__","LWG","Hazard Pointers for C++26","Varna June 2023","","",""
88
"`P2538R1 <https://wg21.link/P2538R1>`__","LWG","ADL-proof ``std::projected``","Varna June 2023","","","|ranges|"
99
"`P2495R3 <https://wg21.link/P2495R3>`__","LWG","Interfacing ``stringstreams`` with ``string_view``","Varna June 2023","","",""
10-
"`P2510R3 <https://wg21.link/P2510R3>`__","LWG","Formatting pointers","Varna June 2023","|In Progress|","","|format|"
10+
"`P2510R3 <https://wg21.link/P2510R3>`__","LWG","Formatting pointers","Varna June 2023","|Complete| [#note-P2510R3]_","17.0","|format|"
1111
"`P2198R7 <https://wg21.link/P2198R7>`__","LWG","Freestanding Feature-Test Macros and Implementation-Defined Extensions","Varna June 2023","","",""
1212
"`P2338R4 <https://wg21.link/P2338R4>`__","LWG","Freestanding Library: Character primitives and the C library","Varna June 2023","","",""
1313
"`P2013R5 <https://wg21.link/P2013R5>`__","LWG","Freestanding Language: Optional ``::operator new``","Varna June 2023","","",""

libcxx/docs/Status/FormatIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Number,Name,Standard,Assignee,Status,First released version
1414
"`P2675R1 <https://wg21.link/P2675R1>`__","``format``'s width estimation is too approximate and not forward compatible","C++23","Mark de Wever","|Complete|",17.0
1515
"`P2572R1 <https://wg21.link/P2572R1>`__","``std::format`` fill character allowances","C++23","Mark de Wever","|Complete|",17.0
1616
"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","C++23","Mark de Wever","|In progress|"
17-
"`P2510R3 <https://wg21.link/P2510R3>`__","Formatting pointers","C++26","Mark de Wever","|In Progress|",
17+
"`P2510R3 <https://wg21.link/P2510R3>`__","Formatting pointers","C++26","Mark de Wever","|Complete|", 17.0
1818
"`P2757R3 <https://wg21.link/P2757R3>`__","Type-checking format args","C++26","","",
1919
"`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","C++26","","",
2020
`P1361 <https://wg21.link/P1361>`_,"Integration of chrono with text formatting","C++20",Mark de Wever,|In Progress|,

libcxx/docs/UsingLibcxx.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ versions. This allows the library to have better estimates for newly introduced
537537
Unicode code points, without requiring the user to use the latest C++ version
538538
in their code base.
539539

540+
In C++26 formatting pointers gained a type ``P`` and allows to use
541+
zero-padding. These options have been retroactively applied to C++20.
542+
540543
Turning off ASan annotation in containers
541544
-----------------------------------------
542545

libcxx/include/__format/formatter_pointer.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,15 @@ struct _LIBCPP_TEMPLATE_VIS __formatter_pointer {
4343
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const void* __ptr, _FormatContext& __ctx) const {
4444
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
4545
__specs.__std_.__alternate_form_ = true;
46-
__specs.__std_.__type_ = __format_spec::__type::__hexadecimal_lower_case;
46+
__specs.__std_.__type_ =
47+
__specs.__std_.__type_ == __format_spec::__type::__pointer_upper_case
48+
? __format_spec::__type::__hexadecimal_upper_case
49+
: __format_spec::__type::__hexadecimal_lower_case;
50+
4751
return __formatter::__format_integer(reinterpret_cast<uintptr_t>(__ptr), __ctx, __specs);
4852
}
4953

50-
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
54+
__format_spec::__parser<_CharT> __parser_;
5155
};
5256

5357
// [format.formatter.spec]/2.4

libcxx/include/__format/parser_std_format_spec.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ inline constexpr __fields __fields_floating_point{
151151
.__locale_specific_form_ = true,
152152
.__type_ = true};
153153
inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true};
154-
inline constexpr __fields __fields_pointer{.__type_ = true};
154+
inline constexpr __fields __fields_pointer{.__zero_padding_ = true, .__type_ = true};
155155

156156
# if _LIBCPP_STD_VER >= 23
157157
inline constexpr __fields __fields_tuple{.__use_range_fill_ = true};
@@ -189,7 +189,8 @@ enum class _LIBCPP_ENUM_VIS __type : uint8_t {
189189
__decimal,
190190
__hexadecimal_lower_case,
191191
__hexadecimal_upper_case,
192-
__pointer,
192+
__pointer_lower_case,
193+
__pointer_upper_case,
193194
__char,
194195
__hexfloat_lower_case,
195196
__hexfloat_upper_case,
@@ -675,7 +676,10 @@ class _LIBCPP_TEMPLATE_VIS __parser {
675676
__type_ = __type::__octal;
676677
break;
677678
case 'p':
678-
__type_ = __type::__pointer;
679+
__type_ = __type::__pointer_lower_case;
680+
break;
681+
case 'P':
682+
__type_ = __type::__pointer_upper_case;
679683
break;
680684
case 's':
681685
__type_ = __type::__string;
@@ -840,7 +844,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_C
840844
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type) {
841845
switch (__type) {
842846
case __format_spec::__type::__default:
843-
case __format_spec::__type::__pointer:
847+
case __format_spec::__type::__pointer_lower_case:
848+
case __format_spec::__type::__pointer_upper_case:
844849
break;
845850

846851
default:

libcxx/test/std/containers/container.adaptors/container.adaptors.format/format.functions.tests.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,9 @@ void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& inpu
717717
check_exception("The format-spec should consume the input or end with a '}'", SV("{::#}"), input);
718718

719719
// *** zero-padding ***
720-
check_exception("A format-spec width field shouldn't have a leading zero", SV("{::05}"), input);
720+
check(SV("[0x0000]"), SV("{::06}"), input);
721+
check(SV("[0x0000]"), SV("{::06p}"), input);
722+
check(SV("[0X0000]"), SV("{::06P}"), input);
721723

722724
// *** precision ***
723725
check_exception("The format-spec should consume the input or end with a '}'", SV("{::.}"), input);
@@ -726,7 +728,7 @@ void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& inpu
726728
check_exception("The format-spec should consume the input or end with a '}'", SV("{::L}"), input);
727729

728730
// *** type ***
729-
for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("p"))
731+
for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("pP"))
730732
check_exception("The format-spec type has a type not supported for a pointer argument", fmt, input);
731733

732734
// ***** Both have a format-spec

libcxx/test/std/utilities/format/format.functions/format_tests.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ case #T[0]:
3737
break;
3838

3939
#if TEST_STD_VER > 20
40-
constexpr std::string_view types = "aAbBcdeEfFgGopsxX?";
40+
constexpr std::string_view types = "aAbBcdeEfFgGopPsxX?";
4141
#else
42-
constexpr std::string_view types = "aAbBcdeEfFgGopsxX";
42+
constexpr std::string_view types = "aAbBcdeEfFgGopPsxX";
4343
#endif
4444

4545
for (auto type : types) {
@@ -61,6 +61,7 @@ case #T[0]:
6161
CASE(G)
6262
CASE(o)
6363
CASE(p)
64+
CASE(P)
6465
CASE(s)
6566
CASE(x)
6667
CASE(X)
@@ -2547,6 +2548,11 @@ void format_test_pointer(TestFunction check, ExceptionTest check_exception) {
25472548
check(SV("answer is '0x0:::'"), SV("answer is '{::<6}'"), P(nullptr));
25482549
check(SV("answer is ':0x0::'"), SV("answer is '{::^6}'"), P(nullptr));
25492550

2551+
// Test whether zero padding is ignored
2552+
check(SV("answer is ':::0x0'"), SV("answer is '{::>06}'"), P(nullptr));
2553+
check(SV("answer is '0x0:::'"), SV("answer is '{::<06}'"), P(nullptr));
2554+
check(SV("answer is ':0x0::'"), SV("answer is '{::^06}'"), P(nullptr));
2555+
25502556
// *** Sign ***
25512557
check_exception("The format-spec should consume the input or end with a '}'", SV("{:-}"), P(nullptr));
25522558
check_exception("The format-spec should consume the input or end with a '}'", SV("{:+}"), P(nullptr));
@@ -2556,7 +2562,9 @@ void format_test_pointer(TestFunction check, ExceptionTest check_exception) {
25562562
check_exception("The format-spec should consume the input or end with a '}'", SV("{:#}"), P(nullptr));
25572563

25582564
// *** zero-padding ***
2559-
check_exception("A format-spec width field shouldn't have a leading zero", SV("{:0}"), P(nullptr));
2565+
check(SV("answer is '0x0000'"), SV("answer is '{:06}'"), P(nullptr));
2566+
check(SV("answer is '0x0000'"), SV("answer is '{:06p}'"), P(nullptr));
2567+
check(SV("answer is '0X0000'"), SV("answer is '{:06P}'"), P(nullptr));
25602568

25612569
// *** precision ***
25622570
check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), P(nullptr));
@@ -2565,7 +2573,7 @@ void format_test_pointer(TestFunction check, ExceptionTest check_exception) {
25652573
check_exception("The format-spec should consume the input or end with a '}'", SV("{:L}"), P(nullptr));
25662574

25672575
// *** type ***
2568-
for (const auto& fmt : invalid_types<CharT>("p"))
2576+
for (const auto& fmt : invalid_types<CharT>("pP"))
25692577
check_exception("The format-spec type has a type not supported for a pointer argument", fmt, P(nullptr));
25702578
}
25712579

libcxx/test/std/utilities/format/format.range/format.range.fmtset/format.functions.tests.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,9 @@ void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& inpu
886886
check_exception("The format-spec should consume the input or end with a '}'", SV("{::#}"), input);
887887

888888
// *** zero-padding ***
889-
check_exception("A format-spec width field shouldn't have a leading zero", SV("{::05}"), input);
889+
check(SV("{0x0000}"), SV("{::06}"), input);
890+
check(SV("{0x0000}"), SV("{::06p}"), input);
891+
check(SV("{0X0000}"), SV("{::06P}"), input);
890892

891893
// *** precision ***
892894
check_exception("The format-spec should consume the input or end with a '}'", SV("{::.}"), input);
@@ -895,7 +897,7 @@ void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& inpu
895897
check_exception("The format-spec should consume the input or end with a '}'", SV("{::L}"), input);
896898

897899
// *** type ***
898-
for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("p"))
900+
for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("pP"))
899901
check_exception("The format-spec type has a type not supported for a pointer argument", fmt, input);
900902

901903
// ***** Both have a format-spec

libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,9 @@ void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& inpu
700700
check_exception("The format-spec should consume the input or end with a '}'", SV("{::#}"), input);
701701

702702
// *** zero-padding ***
703-
check_exception("A format-spec width field shouldn't have a leading zero", SV("{::05}"), input);
703+
check(SV("[0x0000]"), SV("{::06}"), input);
704+
check(SV("[0x0000]"), SV("{::06p}"), input);
705+
check(SV("[0X0000]"), SV("{::06P}"), input);
704706

705707
// *** precision ***
706708
check_exception("The format-spec should consume the input or end with a '}'", SV("{::.}"), input);
@@ -709,7 +711,7 @@ void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& inpu
709711
check_exception("The format-spec should consume the input or end with a '}'", SV("{::L}"), input);
710712

711713
// *** type ***
712-
for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("p"))
714+
for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("pP"))
713715
check_exception("The format-spec type has a type not supported for a pointer argument", fmt, input);
714716

715717
// ***** Both have a format-spec

libcxx/test/std/utilities/format/format.tuple/format.functions.tests.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void test_tuple_or_pair_int_int(TestFunction check, ExceptionTest check_exceptio
6767
check(SV("__42: 99___"), SV("{:_^11m}"), input);
6868
check(SV("__42, 99___"), SV("{:_^11n}"), input);
6969

70-
for (CharT c : SV("aAbBcdeEfFgGopsxX?")) {
70+
for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
7171
check_exception("The format-spec should consume the input or end with a '}'",
7272
std::basic_string_view{STR("{:") + c + STR("}")},
7373
input);
@@ -114,7 +114,7 @@ void test_tuple_or_pair_int_string(TestFunction check, ExceptionTest check_excep
114114
check(SV("__42: \"hello\"___"), SV("{:_^16m}"), input);
115115
check(SV("__42, \"hello\"___"), SV("{:_^16n}"), input);
116116

117-
for (CharT c : SV("aAbBcdeEfFgGopsxX?")) {
117+
for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
118118
check_exception("The format-spec should consume the input or end with a '}'",
119119
std::basic_string_view{STR("{:") + c + STR("}")},
120120
input);
@@ -204,7 +204,7 @@ void test_tuple_int(TestFunction check, ExceptionTest check_exception) {
204204
check_exception("The format specifier m requires a pair or a two-element tuple", SV("{:m}"), input);
205205
check(SV("__42___"), SV("{:_^7n}"), input);
206206

207-
for (CharT c : SV("aAbBcdeEfFgGopsxX?")) {
207+
for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
208208
check_exception("The format-spec should consume the input or end with a '}'",
209209
std::basic_string_view{STR("{:") + c + STR("}")},
210210
input);
@@ -253,7 +253,7 @@ void test_tuple_int_string_color(TestFunction check, ExceptionTest check_excepti
253253
check_exception("The format specifier m requires a pair or a two-element tuple", SV("{:m}"), input);
254254
check(SV("__42, \"hello\", \"red\"___"), SV("{:_^23n}"), input);
255255

256-
for (CharT c : SV("aAbBcdeEfFgGopsxX?")) {
256+
for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
257257
check_exception("The format-spec should consume the input or end with a '}'",
258258
std::basic_string_view{STR("{:") + c + STR("}")},
259259
input);
@@ -326,7 +326,7 @@ void test_nested(TestFunction check, ExceptionTest check_exception, Nested&& inp
326326
check(SV("__42: (\"hello\", \"red\")___"), SV("{:_^25m}"), input);
327327
check(SV("__42, (\"hello\", \"red\")___"), SV("{:_^25n}"), input);
328328

329-
for (CharT c : SV("aAbBcdeEfFgGopsxX?")) {
329+
for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
330330
check_exception("The format-spec should consume the input or end with a '}'",
331331
std::basic_string_view{STR("{:") + c + STR("}")},
332332
input);

libcxx/test/support/format.functions.common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ std::basic_string<CharT> get_colons() {
205205
}
206206

207207
constexpr std::string_view get_format_types() {
208-
return "aAbBcdeEfFgGopsxX"
208+
return "aAbBcdeEfFgGopPsxX"
209209
#if TEST_STD_VER > 20
210210
"?"
211211
#endif

libcxx/utils/generate_feature_test_macro_components.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ def add_version_header(tc):
462462
# "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
463463
},
464464
# Note these three papers are adopted at the June 2023 meeting and have sequential numbering
465-
# 202304 P2510R3 Formatting pointers
465+
# 202304 P2510R3 Formatting pointers (Implemented)
466466
# 202305 P2757R3 Type-checking format args
467467
# 202306 P2637R3 Member Visit
468468
"headers": ["format"],

0 commit comments

Comments
 (0)