From patchwork Fri Nov 11 05:30:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 18470 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp555129wru; Thu, 10 Nov 2022 21:32:23 -0800 (PST) X-Google-Smtp-Source: AA0mqf5HD367YMF8A0QlbSvA7FCf7j0tSbdkGBHYUzwyfOWq8az3UypCXnOpoGX6X2Q3F7lr5DrO X-Received: by 2002:a17:906:1f0c:b0:78d:cd72:8e3e with SMTP id w12-20020a1709061f0c00b0078dcd728e3emr634560ejj.212.1668144743819; Thu, 10 Nov 2022 21:32:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668144743; cv=none; d=google.com; s=arc-20160816; b=bdRQdgTal4wCXaG0K+lQhU6i1JTUFONpvxPuRLj4KQLD6ij2FS42+Jz4+JS3CktYfz aHtXv9hL04ftLB0AliJ65gaLHfX6okthRlQz1rMxVwGGKLEwdPhBtdsvsJuU+81/U+NL I9Jy4gf6xNz5JoT0OStxPcpVVb6NKnWwgSGnp8i5MYFIcU6uRovRs1o2JWAoKqIpIjNk C9AkCOFr29U9ODuiH4m+6x4gxN82hc7NaERNnvfISAhhYcTYSyJ5f+pK6JFj59eA+bU6 0xYys0/7El7MYVUi04h20XwL8bzon0W04qQRuP7hd94RjHIzuCTihMIZSfbaEgOqYiUH Rgcw== 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=CHqN/kQWAOMJD4PhtBLwQRfnH3kGUXbb/wmF0W0vxBQ=; b=BGTA2F/iTc/S7OcLp6QUuQ6glrrkk1S66cnF6rjsfL9w6gW7xPwlZLDgNrPy5Kfp1G /79A3Kb3S/yW/1BYfdjZEwI0x+trhsS5IF6oGVv4/WFoTNr2COy7w2QOXuJ6uPM8vcTB nLxN18SZpuqohIjzKYOGLeV4TD/DOouI3gBVbZgChioLUwE6+tRCg62mMUzfbexRdrWP AKQU6Oh6G1fAauTHyx/Elbd/hH9Ev7gQtXxXocxc4Wclo6Jl8OidQjDoeNdwW0QViiCv YpID9jpCXJVITzYuMMFHZ+2fZOFjzjnbDrsF33T/NEveWCeAwr0eP5/KiLExfL/fM5ue W3Vw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=odHgbmhB; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c 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. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id dm12-20020a170907948c00b0078dad42f75dsi933462ejc.475.2022.11.10.21.32.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Nov 2022 21:32:23 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=odHgbmhB; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c 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 41ACC3858CDA for ; Fri, 11 Nov 2022 05:31:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 41ACC3858CDA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1668144698; bh=CHqN/kQWAOMJD4PhtBLwQRfnH3kGUXbb/wmF0W0vxBQ=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=odHgbmhBlkIbEE9cOvOGnOHyZJTqq55ca0WAoe8u9qVqkNQFgu1jVEKvj+MTEGAb5 Z5RU3JnH0f2Hotog3S4162d+ObLgxvwEo5ANMy5aBG1+vAecGmKIiaJBVtianF4XJe GBIXseoPevIBiDv+8eNf94uvIMBOjKyQsPFLRHSs= 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.133.124]) by sourceware.org (Postfix) with ESMTPS id DBEB23858C60 for ; Fri, 11 Nov 2022 05:30:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DBEB23858C60 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-312-YKhOUwSKOi-hSIZfQA3Lpg-1; Fri, 11 Nov 2022 00:30:45 -0500 X-MC-Unique: YKhOUwSKOi-hSIZfQA3Lpg-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B8172101A528; Fri, 11 Nov 2022 05:30:44 +0000 (UTC) Received: from localhost (unknown [10.33.36.199]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4BD9763A54; Fri, 11 Nov 2022 05:30:44 +0000 (UTC) To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Avoid redundant checks in std::use_facet [PR103755] Date: Fri, 11 Nov 2022 05:30:43 +0000 Message-Id: <20221111053043.563832-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 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, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=unavailable 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?1749176542941277506?= X-GMAIL-MSGID: =?utf-8?q?1749176542941277506?= As discussed in the PR, this makes it three times faster to construct iostreams objects. Tested x86_64-linux. Pushed to trunk. -- >8 -- We do not need to do bounds checks or a runtime dynamic_cast when using std::has_facet and std::use_facet to access the default facets that are guaranteed to be present in every std::locale object. We can just index straight into the array and use a static_cast for the conversion. This patch adds a new std::__try_use_facet function that is like std::use_facet but returns a pointer, so can be used to implement both std::has_facet and std::use_facet. We can then do the necessary metaprogramming to skip the redundant checks in std::__try_use_facet. To avoid having to export (or hide) instantiations of the new function from libstdc++.so the instantiations are given hidden visibility. This allows them to be used in the library, but user code will instantiate it again using the definition in the header. That would happen anyway, because there are no explicit instantiation declarations for any of std::has_facet, std::use_facet, or the new std::__try_use_facet. libstdc++-v3/ChangeLog: PR libstdc++/103755 * config/abi/pre/gnu.ver: Tighten patterns for facets in the base version. Add exports for __try_use_facet. * include/bits/basic_ios.tcc (basic_ios::_M_cache_locale): Use __try_use_facet instead of has_facet and use_facet. * include/bits/fstream.tcc (basic_filebuf::basic_filebuf()): Likewise. (basic_filebuf::imbue): Likewise. * include/bits/locale_classes.h (locale, locale::id) (locale::_Impl): Declare __try_use_facet as a friend. * include/bits/locale_classes.tcc (__try_use_facet): Define new function template with special cases for default facets. (has_facet, use_facet): Call __try_use_facet. * include/bits/locale_facets.tcc (__try_use_facet): Declare explicit instantiations. * include/bits/locale_facets_nonio.tcc (__try_use_facet): Likewise. * src/c++11/locale-inst-monetary.h (INSTANTIATE_FACET_ACCESSORS): Use new macro for facet accessor instantiations. * src/c++11/locale-inst-numeric.h (INSTANTIATE_FACET_ACCESSORS): Likewise. * src/c++11/locale-inst.cc (INSTANTIATE_USE_FACET): Define new macro for instantiating __try_use_facet and use_facet. (INSTANTIATE_FACET_ACCESSORS): Define new macro for also defining has_facet. * src/c++98/compatibility-ldbl.cc (__try_use_facet): Instantiate. * testsuite/22_locale/ctype/is/string/89728_neg.cc: Adjust expected errors. --- libstdc++-v3/config/abi/pre/gnu.ver | 43 ++++++- libstdc++-v3/include/bits/basic_ios.tcc | 17 +-- libstdc++-v3/include/bits/fstream.tcc | 8 +- libstdc++-v3/include/bits/locale_classes.h | 12 ++ libstdc++-v3/include/bits/locale_classes.tcc | 99 ++++++++++++++--- libstdc++-v3/include/bits/locale_facets.tcc | 34 +++++- .../include/bits/locale_facets_nonio.tcc | 64 +++++++++++ libstdc++-v3/src/c++11/locale-inst-monetary.h | 8 +- libstdc++-v3/src/c++11/locale-inst-numeric.h | 8 +- libstdc++-v3/src/c++11/locale-inst.cc | 105 ++++-------------- libstdc++-v3/src/c++98/compatibility-ldbl.cc | 8 ++ .../22_locale/ctype/is/string/89728_neg.cc | 5 +- 12 files changed, 276 insertions(+), 135 deletions(-) diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 4d97ec37147..225d6dc482b 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -133,17 +133,18 @@ GLIBCXX_3.4 { # std::logic_error::~l*; # std::[m-r]*; # std::[m]*; - std::messages[^_]*; +# std::messages[^_]*; # std::messages_byname*; - std::money_*; - std::moneypunct[^_]*; +# std::money_*; + std::money_base*; +# std::moneypunct[^_]*; # std::moneypunct_byname*; # std::n[^u]*; std::n[^aueo]*; std::nothrow; std::nu[^m]*; - std::num[^ep]*; - std::numpunct[^_]*; + std::num[^_ep]*; +# std::numpunct[^_]*; # std::numpunct_byname*; std::ostrstream*; # std::out_of_range::o*; @@ -597,28 +598,49 @@ GLIBCXX_3.4 { _ZNSt12ctype_bynameI[cw]ED*; # std::num_get + _ZNSt7num_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[CD][012]*; + _ZNSt7num_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE2idE; _ZNKSt7num_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[2-9]*; _ZNKSt7num_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE14_M_extract_intI*; - _ZNKSt7num_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE16_M_extract_floatI*; + _ZNKSt7num_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE16_M_extract_float*; # std::num_put + _ZNSt7num_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[CD][012]*; + _ZNSt7num_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE2idE; _ZNKSt7num_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[2-9]*; _ZNKSt7num_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE1[234]*; _ZNKSt7num_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE15_M_insert_floatI*; + # std::numpunct + _ZNSt8numpunctI[cw]E[CD][012]*; + _ZNSt8numpunctI[cw]E2idE; + _ZNSt8numpunctI[cw]E[2]*; + _ZNKSt8numpunctI[cw]E[189]*; + # std::numpunct_byname _ZNSt15numpunct_bynameI[cw]EC[12]EPKc[jmy]; _ZNSt15numpunct_bynameI[cw]ED*; # std::money_get + _ZNSt9money_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[CD][012]*; + _ZNSt9money_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE2idE; _ZNKSt9money_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[2-9]*; _ZNKSt9money_getI[cw]St19istreambuf_iteratorI[cw]St11char_traitsI[cw]EEE10_M_extractILb[01]EEES3_S3_S3_RSt8ios_baseRSt12_Ios_IostateRSs; # std::money_put + _ZNSt9money_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[CD][012]*; + _ZNSt9money_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE2idE; _ZNKSt9money_putI[cw]St19ostreambuf_iteratorI[cw]St11char_traitsI[cw]EEE[1-8]*; _ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE9_M_insertILb[01]EEES3_S3_RSt8ios_basecRKSs; _ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE9_M_insertILb[01]EEES3_S3_RSt8ios_basewRKSbIwS2_SaIwEE; + # std::moneypunct + _ZNSt10moneypunctI[cw]Lb[01]EE[CD][012]*; + _ZNSt10moneypunctI[cw]Lb[01]EE2idE; + _ZNSt10moneypunctI[cw]Lb[01]EE24*; + _ZNSt10moneypunctI[cw]Lb[01]EE4intlE; + _ZNKSt10moneypunctI[cw]Lb[01]EE[18]*; + # std::moneypunct_byname _ZNSt17moneypunct_bynameI[cw]Lb[01]EEC[12]EPKc[jmy]; _ZNSt17moneypunct_bynameI[cw]Lb[01]EED*; @@ -657,6 +679,11 @@ GLIBCXX_3.4 { _ZNSt14numeric_limitsI[a-m]E1[0-7]max_e*; _ZNSt14numeric_limitsI[p-z]E1[0-7]max_e*; + # std::messages + _ZNSt8messagesI[cw]E[CD][012]*; + _ZNSt8messagesI[cw]E2idE; + _ZNKSt8messagesI[cw]E[1-8]*; + # std::messages_byname _ZNSt15messages_bynameI[cw]EC[12]EPKc[jmy]; _ZNSt15messages_bynameI[cw]ED*; @@ -2446,6 +2473,7 @@ GLIBCXX_3.4.30 { GLIBCXX_3.4.31 { _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE15_M_replace_cold*; + _ZSt20__to_chars_float16_tPcS_fSt12chars_format; _ZSt21__to_chars_bfloat16_tPcS_fSt12chars_format; _ZSt22__from_chars_float16_tPKcS0_RfSt12chars_format; @@ -2454,6 +2482,9 @@ GLIBCXX_3.4.31 { _ZSt8to_charsPcS_DF128_St12chars_format; _ZSt8to_charsPcS_DF128_St12chars_formati; _ZSt10from_charsPKcS0_RDF128_St12chars_format; + + _ZSt15__try_use_facet*; + } GLIBCXX_3.4.30; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/bits/basic_ios.tcc b/libstdc++-v3/include/bits/basic_ios.tcc index 2bbcdc20dc0..15d35a46cf4 100644 --- a/libstdc++-v3/include/bits/basic_ios.tcc +++ b/libstdc++-v3/include/bits/basic_ios.tcc @@ -156,20 +156,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void basic_ios<_CharT, _Traits>::_M_cache_locale(const locale& __loc) { - if (__builtin_expect(has_facet<__ctype_type>(__loc), true)) - _M_ctype = std::__addressof(use_facet<__ctype_type>(__loc)); - else - _M_ctype = 0; - - if (__builtin_expect(has_facet<__num_put_type>(__loc), true)) - _M_num_put = std::__addressof(use_facet<__num_put_type>(__loc)); - else - _M_num_put = 0; - - if (__builtin_expect(has_facet<__num_get_type>(__loc), true)) - _M_num_get = std::__addressof(use_facet<__num_get_type>(__loc)); - else - _M_num_get = 0; + _M_ctype = std::__try_use_facet<__ctype_type>(__loc); + _M_num_put = std::__try_use_facet<__num_put_type>(__loc); + _M_num_get = std::__try_use_facet<__num_get_type>(__loc); } // Inhibit implicit instantiations for required instantiations, diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index 2e936962837..8158ab30312 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -86,8 +86,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0), _M_ext_end(0) { - if (has_facet<__codecvt_type>(this->_M_buf_locale)) - _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); + _M_codecvt = std::__try_use_facet<__codecvt_type>(this->_M_buf_locale); } #if __cplusplus >= 201103L @@ -1028,9 +1027,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { bool __testvalid = true; - const __codecvt_type* _M_codecvt_tmp = 0; - if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) - _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); + const __codecvt_type* const _M_codecvt_tmp + = __try_use_facet<__codecvt_type>(__loc); if (this->is_open()) { diff --git a/libstdc++-v3/include/bits/locale_classes.h b/libstdc++-v3/include/bits/locale_classes.h index 6cad0ff5655..6912a54d607 100644 --- a/libstdc++-v3/include/bits/locale_classes.h +++ b/libstdc++-v3/include/bits/locale_classes.h @@ -82,6 +82,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend const _Facet& use_facet(const locale&); + template + friend const _Facet* + __try_use_facet(const locale&) _GLIBCXX_NOTHROW; + template friend struct __use_cache; @@ -496,6 +500,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend bool has_facet(const locale&) throw(); + template + friend const _Facet* + __try_use_facet(const locale&) _GLIBCXX_NOTHROW; + // NB: There is no accessor for _M_index because it may be used // before the constructor is run; the effect of calling a member // function (even an inline) would be undefined. @@ -536,6 +544,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend const _Facet& use_facet(const locale&); + template + friend const _Facet* + __try_use_facet(const locale&) _GLIBCXX_NOTHROW; + template friend struct __use_cache; diff --git a/libstdc++-v3/include/bits/locale_classes.tcc b/libstdc++-v3/include/bits/locale_classes.tcc index 9cc4f238ee7..7a67f5cd315 100644 --- a/libstdc++-v3/include/bits/locale_classes.tcc +++ b/libstdc++-v3/include/bits/locale_classes.tcc @@ -87,6 +87,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __s2.data(), __s2.data() + __s2.length()) < 0); } + template + inline const _Facet* + __try_use_facet(const locale& __loc) _GLIBCXX_NOTHROW + { + const size_t __i = _Facet::id._M_id(); + const locale::facet** __facets = __loc._M_impl->_M_facets; + + // We know these standard facets are always installed in every locale + // so dynamic_cast always succeeds, just use static_cast instead. +#define _GLIBCXX_STD_FACET(...) \ + if _GLIBCXX17_CONSTEXPR (__is_same(_Facet, __VA_ARGS__)) \ + return static_cast(__facets[__i]) + + _GLIBCXX_STD_FACET(ctype); + _GLIBCXX_STD_FACET(num_get); + _GLIBCXX_STD_FACET(num_put); + _GLIBCXX_STD_FACET(codecvt); + _GLIBCXX_STD_FACET(collate); + _GLIBCXX_STD_FACET(moneypunct); + _GLIBCXX_STD_FACET(moneypunct); + _GLIBCXX_STD_FACET(money_get); + _GLIBCXX_STD_FACET(money_put); + _GLIBCXX_STD_FACET(numpunct); + _GLIBCXX_STD_FACET(time_get); + _GLIBCXX_STD_FACET(time_put); + _GLIBCXX_STD_FACET(messages); + +#ifdef _GLIBCXX_USE_WCHAR_T + _GLIBCXX_STD_FACET(ctype); + _GLIBCXX_STD_FACET(num_get); + _GLIBCXX_STD_FACET(num_put); + _GLIBCXX_STD_FACET(codecvt); + _GLIBCXX_STD_FACET(collate); + _GLIBCXX_STD_FACET(moneypunct); + _GLIBCXX_STD_FACET(moneypunct); + _GLIBCXX_STD_FACET(money_get); + _GLIBCXX_STD_FACET(money_put); + _GLIBCXX_STD_FACET(numpunct); + _GLIBCXX_STD_FACET(time_get); + _GLIBCXX_STD_FACET(time_put); + _GLIBCXX_STD_FACET(messages); +#endif +#ifdef _GLIBCXX_USE_CHAR8_T + _GLIBCXX_STD_FACET(codecvt); +#endif +#if __cplusplus >= 201103L + _GLIBCXX_STD_FACET(codecvt); + _GLIBCXX_STD_FACET(codecvt); +#endif + +#undef _GLIBCXX_STD_FACET + + if (__i >= __loc._M_impl->_M_facets_size || !__facets[__i]) + return 0; + +#if __cpp_rtti + return dynamic_cast(__facets[__i]); +#else + return static_cast(__facets[__i]); +#endif + } + /** * @brief Test for the presence of a facet. * @ingroup locales @@ -100,17 +162,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @return true if @p __loc contains a facet of type _Facet, else false. */ template - bool + inline bool has_facet(const locale& __loc) throw() { - const size_t __i = _Facet::id._M_id(); - const locale::facet** __facets = __loc._M_impl->_M_facets; - return (__i < __loc._M_impl->_M_facets_size -#if __cpp_rtti - && dynamic_cast(__facets[__i])); +#if __cplusplus >= 201103L + static_assert(__is_base_of(locale::facet, _Facet), + "template argument must be derived from locale::facet"); #else - && static_cast(__facets[__i])); + (void) static_cast(static_cast(0)); #endif + return std::__try_use_facet<_Facet>(__loc) != 0; } /** @@ -130,18 +191,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdangling-reference" template - const _Facet& + inline const _Facet& use_facet(const locale& __loc) { - const size_t __i = _Facet::id._M_id(); - const locale::facet** __facets = __loc._M_impl->_M_facets; - if (__i >= __loc._M_impl->_M_facets_size || !__facets[__i]) - __throw_bad_cast(); -#if __cpp_rtti - return dynamic_cast(*__facets[__i]); +#if __cplusplus >= 201103L + static_assert(__is_base_of(locale::facet, _Facet), + "template argument must be derived from locale::facet"); #else - return static_cast(*__facets[__i]); + (void) static_cast(static_cast(0)); #endif + if (const _Facet* __f = std::__try_use_facet<_Facet>(__loc)) + return *__f; + __throw_bad_cast(); } #pragma GCC diagnostic pop @@ -273,6 +334,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION extern template class collate; extern template class collate_byname; + extern template + const collate* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + extern template const collate& use_facet >(const locale&); @@ -285,6 +350,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION extern template class collate; extern template class collate_byname; + extern template + const collate* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + extern template const collate& use_facet >(const locale&); diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc index ec7cce4a640..dd5c45e223b 100644 --- a/libstdc++-v3/include/bits/locale_facets.tcc +++ b/libstdc++-v3/include/bits/locale_facets.tcc @@ -1325,6 +1325,22 @@ _GLIBCXX_END_NAMESPACE_LDBL extern template class _GLIBCXX_NAMESPACE_LDBL num_put; extern template class ctype_byname; + extern template + const ctype* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const numpunct* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const num_put* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const num_get* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + extern template const ctype& use_facet >(const locale&); @@ -1364,6 +1380,22 @@ _GLIBCXX_END_NAMESPACE_LDBL extern template class _GLIBCXX_NAMESPACE_LDBL num_put; extern template class ctype_byname; + extern template + const ctype* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const numpunct* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const num_put* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const num_get* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + extern template const ctype& use_facet >(const locale&); @@ -1380,7 +1412,7 @@ _GLIBCXX_END_NAMESPACE_LDBL const num_get& use_facet >(const locale&); - extern template + extern template bool has_facet >(const locale&); diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.tcc b/libstdc++-v3/include/bits/locale_facets_nonio.tcc index 17a2c8d4486..320bcf22206 100644 --- a/libstdc++-v3/include/bits/locale_facets_nonio.tcc +++ b/libstdc++-v3/include/bits/locale_facets_nonio.tcc @@ -1691,6 +1691,38 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 extern template class messages; extern template class messages_byname; + extern template + const moneypunct* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const moneypunct* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const money_put* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const money_get* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const __timepunct* + __try_use_facet<__timepunct >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const time_put* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const time_get* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const messages* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + extern template const moneypunct& use_facet >(const locale&); @@ -1766,6 +1798,38 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 extern template class messages; extern template class messages_byname; + extern template + const moneypunct* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const moneypunct* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const money_put* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const money_get* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const __timepunct* + __try_use_facet<__timepunct >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const time_put* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const time_get* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + + extern template + const messages* + __try_use_facet >(const locale&) _GLIBCXX_NOTHROW; + extern template const moneypunct& use_facet >(const locale&); diff --git a/libstdc++-v3/src/c++11/locale-inst-monetary.h b/libstdc++-v3/src/c++11/locale-inst-monetary.h index e1c696dc4e3..ff8439857d2 100644 --- a/libstdc++-v3/src/c++11/locale-inst-monetary.h +++ b/libstdc++-v3/src/c++11/locale-inst-monetary.h @@ -32,11 +32,9 @@ namespace std _GLIBCXX_VISIBILITY(default) { - template const money_put& use_facet >(const locale&); - template const money_get& use_facet >(const locale&); - - template bool has_facet >(const locale&); - template bool has_facet >(const locale&); +// use_facet and has_facet instantiations +INSTANTIATE_FACET_ACCESSORS(money_put); +INSTANTIATE_FACET_ACCESSORS(money_get); _GLIBCXX_BEGIN_NAMESPACE_LDBL_OR_CXX11 template class money_get >; diff --git a/libstdc++-v3/src/c++11/locale-inst-numeric.h b/libstdc++-v3/src/c++11/locale-inst-numeric.h index 1417ac25ed4..4b970f75f6e 100644 --- a/libstdc++-v3/src/c++11/locale-inst-numeric.h +++ b/libstdc++-v3/src/c++11/locale-inst-numeric.h @@ -29,11 +29,9 @@ namespace std _GLIBCXX_VISIBILITY(default) { #if ! _GLIBCXX_USE_CXX11_ABI - template const num_get& use_facet >(const locale&); - template const num_put& use_facet >(const locale&); - - template bool has_facet >(const locale&); - template bool has_facet >(const locale&); +// use_facet and has_facet instantiations +INSTANTIATE_FACET_ACCESSORS(num_get); +INSTANTIATE_FACET_ACCESSORS(num_put); #endif _GLIBCXX_BEGIN_NAMESPACE_LDBL diff --git a/libstdc++-v3/src/c++11/locale-inst.cc b/libstdc++-v3/src/c++11/locale-inst.cc index 3aee5df9b04..b264cb381ec 100644 --- a/libstdc++-v3/src/c++11/locale-inst.cc +++ b/libstdc++-v3/src/c++11/locale-inst.cc @@ -43,6 +43,17 @@ # define C_is_char #endif +#define INSTANTIATE_USE_FACET(...) \ + template const __VA_ARGS__* \ + __try_use_facet< __VA_ARGS__ >(const locale&) noexcept; \ + template const __VA_ARGS__& \ + use_facet<__VA_ARGS__>(const locale&) \ + +#define INSTANTIATE_FACET_ACCESSORS(...) \ + INSTANTIATE_USE_FACET(__VA_ARGS__); \ + template bool \ + has_facet<__VA_ARGS__>(const locale&) noexcept + #include "locale-inst-numeric.h" #include "locale-inst-monetary.h" @@ -116,92 +127,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template class collate_byname; _GLIBCXX_END_NAMESPACE_CXX11 - // use_facet +// use_facet and has_facet instantiations #if ! _GLIBCXX_USE_CXX11_ABI - template - const ctype& - use_facet >(const locale&); - - template - const codecvt& - use_facet >(const locale&); +INSTANTIATE_FACET_ACCESSORS(ctype); +INSTANTIATE_FACET_ACCESSORS(codecvt); #endif - - template - const collate& - use_facet >(const locale&); - - template - const numpunct& - use_facet >(const locale&); - - template - const moneypunct& - use_facet >(const locale&); - - template - const moneypunct& - use_facet >(const locale&); - +INSTANTIATE_FACET_ACCESSORS(collate); +INSTANTIATE_FACET_ACCESSORS(numpunct); +INSTANTIATE_FACET_ACCESSORS(moneypunct); +// No explicit instantiation of has_facet> for some reason. +INSTANTIATE_USE_FACET (moneypunct); #if ! _GLIBCXX_USE_CXX11_ABI - template - const __timepunct& - use_facet<__timepunct >(const locale&); - - template - const time_put& - use_facet >(const locale&); +INSTANTIATE_FACET_ACCESSORS(__timepunct); +INSTANTIATE_FACET_ACCESSORS(time_put); #endif - - template - const time_get& - use_facet >(const locale&); - - template - const messages& - use_facet >(const locale&); - - // has_facet -#if ! _GLIBCXX_USE_CXX11_ABI - template - bool - has_facet >(const locale&); - - template - bool - has_facet >(const locale&); -#endif - - template - bool - has_facet >(const locale&); - - template - bool - has_facet >(const locale&); - - template - bool - has_facet >(const locale&); - -#if ! _GLIBCXX_USE_CXX11_ABI - template - bool - has_facet<__timepunct >(const locale&); - - template - bool - has_facet >(const locale&); -#endif - - template - bool - has_facet >(const locale&); - - template - bool - has_facet >(const locale&); - +INSTANTIATE_FACET_ACCESSORS(time_get); +INSTANTIATE_FACET_ACCESSORS(messages); #if ! _GLIBCXX_USE_CXX11_ABI // locale functions. diff --git a/libstdc++-v3/src/c++98/compatibility-ldbl.cc b/libstdc++-v3/src/c++98/compatibility-ldbl.cc index 683f7a8429c..55a59438037 100644 --- a/libstdc++-v3/src/c++98/compatibility-ldbl.cc +++ b/libstdc++-v3/src/c++98/compatibility-ldbl.cc @@ -48,6 +48,10 @@ namespace std _GLIBCXX_VISIBILITY(default) template bool has_facet >(const locale&); template bool has_facet >(const locale&); template bool has_facet >(const locale&); + template const num_put* __try_use_facet >(const locale&); + template const num_get* __try_use_facet >(const locale&); + template const money_put* __try_use_facet >(const locale&); + template const money_get* __try_use_facet >(const locale&); #undef C #ifdef _GLIBCXX_USE_WCHAR_T #define C wchar_t @@ -63,6 +67,10 @@ namespace std _GLIBCXX_VISIBILITY(default) template bool has_facet >(const locale&); template bool has_facet >(const locale&); template bool has_facet >(const locale&); + template const num_put* __try_use_facet >(const locale&); + template const num_get* __try_use_facet >(const locale&); + template const money_put* __try_use_facet >(const locale&); + template const money_get* __try_use_facet >(const locale&); #undef C #endif } diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc index 7935c99a96f..047df40e1d4 100644 --- a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc +++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc @@ -17,14 +17,15 @@ // with this library; see the file COPYING3. If not see // . -// { dg-error "complete" "" { target *-*-* } 0 } -// { dg-error "invalid 'static_cast'" "" { target { ! rtti } } 0 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 0 } +// { dg-error "invalid 'static_cast'" "" { target c++98_only } 0 } #include template struct trait: std::char_traits {}; +// Generates unique types so we get distinct diagnostics for each line. template std::basic_string > make_str() {