From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id B9CBC3857739; Thu, 29 Jun 2023 23:01:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B9CBC3857739 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1688079679; bh=TvUVzYuwuYgv8GZtPJVvbfJm9hR9rhXAuOV//xRl1Wc=; h=From:To:Subject:Date:From; b=KWpSu+UPycsR14On7WiE0DyjpULyxcLCVZCBt7IjsPpLyLIp/LzsAm1PmX7rPPgTH /W85GBvFPwxmdGGnaS/aYFMRh0ecrX17bO9zDgNIu1Dl9WOjIEWgoA/CRWFXwauuTM fnU81+AgpWeC5Gdzhkv//52nGqirEPC+N+NO9low= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-7510] libstdc++: Fix P2510R3 "Formatting pointers" [PR110149] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-13 X-Git-Oldrev: dbd4acd72274f3b3d542ebf68f9962eda8f8b769 X-Git-Newrev: ae7cdc8c0f5278e7941f1de7c72ffe9f1fed2775 Message-Id: <20230629230119.B9CBC3857739@sourceware.org> Date: Thu, 29 Jun 2023 23:01:19 +0000 (GMT) List-Id: https://gcc.gnu.org/g:ae7cdc8c0f5278e7941f1de7c72ffe9f1fed2775 commit r13-7510-gae7cdc8c0f5278e7941f1de7c72ffe9f1fed2775 Author: Jonathan Wakely Date: Thu Jun 8 21:35:21 2023 +0100 libstdc++: Fix P2510R3 "Formatting pointers" [PR110149] I had intended to support the P2510R3 proposal unconditionally in C++20 mode, but I left it half implemented. The parse function supported the new extensions, but the format function didn't. This adds the missing pieces, and makes it only enabled for C++26 and non-strict modes. libstdc++-v3/ChangeLog: PR libstdc++/110149 * include/std/format (formatter::parse): Only alow 0 and P for C++26 and non-strict modes. (formatter::format): Use toupper for P type, and insert zero-fill characters for 0 option. * testsuite/std/format/functions/format.cc: Check pointer formatting. Only check P2510R3 extensions conditionally. * testsuite/std/format/parse_ctx.cc: Only check P2510R3 extensions conditionally. (cherry picked from commit 628ba410b9265dbd4278c1f1b1fadf05348adef2) Diff: --- libstdc++-v3/include/std/format | 56 +++++++++++++++++++--- .../testsuite/std/format/functions/format.cc | 42 ++++++++++++++++ libstdc++-v3/testsuite/std/format/parse_ctx.cc | 15 ++++-- 3 files changed, 101 insertions(+), 12 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 6edc3208afa..96a1e62ccc8 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -830,7 +830,7 @@ namespace __format { if (_M_spec._M_type == _Pres_esc) { - // TODO: C++20 escaped string presentation + // TODO: C++23 escaped string presentation } if (_M_spec._M_width_kind == _WP_none @@ -2081,19 +2081,31 @@ namespace __format if (__finished()) return __first; - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // P2519R3 Formatting pointers +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// P2510R3 Formatting pointers +#define _GLIBCXX_P2518R3 (__cplusplus > 202302L || ! defined __STRICT_ANSI__) + +#if _GLIBCXX_P2518R3 __first = __spec._M_parse_zero_fill(__first, __last); if (__finished()) return __first; +#endif __first = __spec._M_parse_width(__first, __last, __pc); - if (__first != __last && (*__first == 'p' || *__first == 'P')) + if (__first != __last) { - if (*__first == 'P') + if (*__first == 'p') + ++__first; +#if _GLIBCXX_P2518R3 + else if (*__first == 'P') + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // P2510R3 Formatting pointers __spec._M_type = __format::_Pres_P; - ++__first; + ++__first; + } +#endif } if (__finished()) @@ -2110,9 +2122,21 @@ namespace __format char __buf[2 + sizeof(__v) * 2]; auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), __u, 16); - const int __n = __ptr - __buf; + int __n = __ptr - __buf; __buf[0] = '0'; __buf[1] = 'x'; +#if _GLIBCXX_P2518R3 + if (_M_spec._M_type == __format::_Pres_P) + { + __buf[1] = 'X'; + for (auto __p = __buf + 2; __p != __ptr; ++__p) +#if __has_builtin(__builtin_toupper) + *__p = __builtin_toupper(*__p); +#else + *__p = std::toupper(*__p); +#endif + } +#endif basic_string_view<_CharT> __str; if constexpr (is_same_v<_CharT, char>) @@ -2126,6 +2150,24 @@ namespace __format __str = wstring_view(__p, __n); } +#if _GLIBCXX_P2518R3 + if (_M_spec._M_zero_fill) + { + size_t __width = _M_spec._M_get_width(__fc); + if (__width <= __str.size()) + return __format::__write(__fc.out(), __str); + + auto __out = __fc.out(); + // Write "0x" or "0X" prefix before zero-filling. + __out = __format::__write(std::move(__out), __str.substr(0, 2)); + __str.remove_prefix(2); + size_t __nfill = __width - __n; + return __format::__write_padded(std::move(__out), __str, + __format::_Align_right, + __nfill, _CharT('0')); + } +#endif + return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec, __format::_Align_right); } diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc index 2a1b1560394..3485535e3cb 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc @@ -206,6 +206,8 @@ test_width() VERIFY( s == " " ); s = std::format("{:{}}", "", 3); VERIFY( s == " " ); + s = std::format("{:{}}|{:{}}", 1, 2, 3, 4); + VERIFY( s == " 1| 3" ); s = std::format("{1:{0}}", 2, ""); VERIFY( s == " " ); s = std::format("{:03}", 9); @@ -342,6 +344,45 @@ test_float128() #endif } +void +test_pointer() +{ + void* p = nullptr; + const void* pc = p; + std::string s, str_int; + + s = std::format("{} {} {}", p, pc, nullptr); + VERIFY( s == "0x0 0x0 0x0" ); + s = std::format("{:p} {:p} {:p}", p, pc, nullptr); + VERIFY( s == "0x0 0x0 0x0" ); + s = std::format("{:4},{:5},{:6}", p, pc, nullptr); // width + VERIFY( s == " 0x0, 0x0, 0x0" ); + s = std::format("{:<4},{:>5},{:^7}", p, pc, nullptr); // align+width + VERIFY( s == "0x0 , 0x0, 0x0 " ); + s = std::format("{:o<4},{:o>5},{:o^7}", p, pc, nullptr); // fill+align+width + VERIFY( s == "0x0o,oo0x0,oo0x0oo" ); + + pc = p = &s; + str_int = std::format("{:#x}", reinterpret_cast(p)); + s = std::format("{} {} {}", p, pc, nullptr); + VERIFY( s == (str_int + ' ' + str_int + " 0x0") ); + str_int = std::format("{:#20x}", reinterpret_cast(p)); + s = std::format("{:20} {:20p}", p, pc); + VERIFY( s == (str_int + ' ' + str_int) ); + +#if __cplusplus > 202302L || ! defined __STRICT_ANSI__ + // P2510R3 Formatting pointers + s = std::format("{:06} {:07P} {:08p}", (void*)0, (const void*)0, nullptr); + VERIFY( s == "0x0000 0X00000 0x000000" ); + str_int = std::format("{:#016x}", reinterpret_cast(p)); + s = std::format("{:016} {:016}", p, pc); + VERIFY( s == (str_int + ' ' + str_int) ); + str_int = std::format("{:#016X}", reinterpret_cast(p)); + s = std::format("{:016P} {:016P}", p, pc); + VERIFY( s == (str_int + ' ' + str_int) ); +#endif +} + int main() { test_no_args(); @@ -354,4 +395,5 @@ int main() test_minmax(); test_p1652r1(); test_float128(); + test_pointer(); } diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc b/libstdc++-v3/testsuite/std/format/parse_ctx.cc index 069dfceced5..260caf123d0 100644 --- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc +++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc @@ -244,10 +244,6 @@ test_pointer() VERIFY( ! is_std_format_spec_for("-") ); VERIFY( ! is_std_format_spec_for(" ") ); VERIFY( ! is_std_format_spec_for("#") ); - VERIFY( is_std_format_spec_for("0p") ); // P2510 - VERIFY( is_std_format_spec_for("0") ); - VERIFY( ! is_std_format_spec_for("00p") ); - VERIFY( is_std_format_spec_for("01p") ); VERIFY( is_std_format_spec_for("1") ); VERIFY( ! is_std_format_spec_for("-1") ); VERIFY( ! is_std_format_spec_for("-1p") ); @@ -263,7 +259,6 @@ test_pointer() VERIFY( ! is_std_format_spec_for("s") ); VERIFY( ! is_std_format_spec_for("?") ); VERIFY( is_std_format_spec_for("p") ); - VERIFY( is_std_format_spec_for("P") ); VERIFY( ! is_std_format_spec_for("a") ); VERIFY( ! is_std_format_spec_for("A") ); VERIFY( ! is_std_format_spec_for("f") ); @@ -271,6 +266,16 @@ test_pointer() VERIFY( ! is_std_format_spec_for("g") ); VERIFY( ! is_std_format_spec_for("G") ); VERIFY( ! is_std_format_spec_for("+p") ); + +#if __cplusplus > 202302L || ! defined __STRICT_ANSI__ + // As an extension, we support P2510R3 Formatting pointers + VERIFY( is_std_format_spec_for("P") ); + VERIFY( is_std_format_spec_for("0p") ); + VERIFY( is_std_format_spec_for("0P") ); + VERIFY( is_std_format_spec_for("0") ); + VERIFY( is_std_format_spec_for("01p") ); + VERIFY( ! is_std_format_spec_for("00p") ); +#endif } void