From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 5A48D3857BA4 for ; Fri, 9 Jun 2023 12:10:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5A48D3857BA4 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686312629; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gboe8wx7Pa46M+N23eFfzvPGjsnVeKHK70/XwHwaPls=; b=OP2qwYvejWofClSyGKeuqehI/TcRYbFu2k76hdDY43XvDjY11AyxIV1oUGo+MBRdLhCJH5 BgyDkUoe/lkCoxzOXg8jDv3hHcrx585/YdOLI5ZGGgT8XKB+CXcgO71IrvZ7N1z1FhXvO7 FwMUOHXg5K1Cgz2knLbjIKG/CMd3Mtc= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-475-tartCCdaNvuADp9eR8TTMw-1; Fri, 09 Jun 2023 08:10:27 -0400 X-MC-Unique: tartCCdaNvuADp9eR8TTMw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 69CFC8027F5; Fri, 9 Jun 2023 12:10:27 +0000 (UTC) Received: from localhost (unknown [10.42.28.139]) by smtp.corp.redhat.com (Postfix) with ESMTP id 30C781121314; Fri, 9 Jun 2023 12:10:27 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Fix P2510R3 "Formatting pointers" [PR110149] Date: Fri, 9 Jun 2023 13:10:25 +0100 Message-Id: <20230609121025.294493-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Tested powerpc64le-linux. Pushed to trunk. I'll backport it to gcc-13 later. -- >8 -- 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. --- libstdc++-v3/include/std/format | 56 ++++++++++++++++--- .../testsuite/std/format/functions/format.cc | 42 ++++++++++++++ .../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 -- 2.40.1