From patchwork Fri Jun 9 12:10:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 105583 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp898617vqr; Fri, 9 Jun 2023 05:11:45 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4PyGgRzilr+YI4rm3CT/+0pxrCpnt2vj1K+1ya+zYvJXtpMOmdAnQphLMfsLSDuebaszFD X-Received: by 2002:a17:907:2d86:b0:96a:ee54:9f19 with SMTP id gt6-20020a1709072d8600b0096aee549f19mr1894885ejc.48.1686312705620; Fri, 09 Jun 2023 05:11:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1686312705; cv=none; d=google.com; s=arc-20160816; b=bN/RTzoC8nM/HIX7iy7l/HqCB7wXMNiUxYy4OPqsBtt0ohjpwF4tP3azCM9v48Gx/w CBYGAgpzJeOW2rOdZGxYFMNikoXoUNKhkvJ2tMhyBNzJaWplD05HLqFz3RWkyFBa0rfu 6Vhl1e1YiuKvECA3jh5qUwYg6QI5Is7XPH+m60BgkCKjrK5vVeA9gT+lnAvcMZ3ilfgL BPsU2KQrVKTm4GZeiId6TxtuBT2OSHwhzrpjVvJdoT+ha6WDpSVtXsBl6Xo2bE0ICSGz 2BqKMBe2TieoTOwZCPLul4arjGgTlpCbtVwgfCmAvukq0RT99hCxdDBFK+bvY4mPBvPk dfuA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:message-id:date:subject:to :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=gboe8wx7Pa46M+N23eFfzvPGjsnVeKHK70/XwHwaPls=; b=y6GDJlSrnz3nXfUpxb0HyYoFptHqm1LtrPh5d9XWkjXzWBtsvmz0snhdeRcDRC2xJo UlnPlo6dgUcxjxqvTHcylbjnGxMTUhTgWTxGXn1k4g4n+u1jp2znFZOF8D+TqUUfg+oJ /Q8Yh2YQi6GQaqIw7PCNOFfFhGMqM70eHcNkzpLRR2z4+g+vOWJsbYF1M7QIuaaCwkf0 jL3zCBc4OowIOXGbMF3l72MdxY/9pD/vCNFbSICw6onwpoxP7XRL8zMdUBmlU0m0dHUX RsZNXNafuwD7AR1FQjyhsg4OOcjJzdq+kxw+tlC8tlyxL/3brYCFicwtNHCyN7E3yx25 r+UA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=B3QieCAF; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id g15-20020a1709064e4f00b0096f8736bffcsi1168624ejw.666.2023.06.09.05.11.45 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jun 2023 05:11:45 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=B3QieCAF; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8FF443856619 for ; Fri, 9 Jun 2023 12:11:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8FF443856619 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1686312674; bh=gboe8wx7Pa46M+N23eFfzvPGjsnVeKHK70/XwHwaPls=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=B3QieCAF0cK19kS9cdqjfhD9/cmEKYE/0+z4iiG0U12Mi2ay5qcddcV4/Hm30bwFe s6u9/84zM67+0phujAA0hrN6icfDvYbCjPa1MKV2SAkQh9t4Fo2qTgPecg/9mhbWCY shwjzMGb3MlkRB/k+7IpMpxi50V6MbskHKhyO5rA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org 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 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) 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 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 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1768227032019130166?= X-GMAIL-MSGID: =?utf-8?q?1768227032019130166?= 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