[committed] libstdc++: Avoid redundant checks in std::use_facet [PR103755]
Checks
Commit Message
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(-)
Comments
On 11/11/22 06:30, Jonathan Wakely via Gcc-patches wrote:
> As discussed in the PR, this makes it three times faster to construct
> iostreams objects.
>
> Tested x86_64-linux. Pushed to trunk.
I haven't yet tried to track down what's going on, but with various
versions of Clang (e.g. clang-15.0.4-1.fc37.x86_64):
> $ cat test.cc
> #include <regex>
> int main(int, char ** argv) {
> std::regex_traits<char>().transform(argv[0], argv[0] + 1);
> }
> $ clang++ --gcc-toolchain=... -fsanitize=undefined -O2 test.cc
> /usr/bin/ld: /tmp/test-c112b1.o: in function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::__cxx11::regex_traits<char>::transform<char*>(char*, char*) const':
> test.cc:(.text._ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_[_ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_]+0x1b): undefined reference to `std::__cxx11::collate<char> const* std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)'
> clang-15: error: linker command failed with exit code 1 (use -v to see invocation)
On Fri, 11 Nov 2022 at 21:00, Stephan Bergmann <sbergman@redhat.com> wrote:
>
> On 11/11/22 06:30, Jonathan Wakely via Gcc-patches wrote:
> > As discussed in the PR, this makes it three times faster to construct
> > iostreams objects.
> >
> > Tested x86_64-linux. Pushed to trunk.
>
> I haven't yet tried to track down what's going on, but with various
> versions of Clang (e.g. clang-15.0.4-1.fc37.x86_64):
>
> > $ cat test.cc
> > #include <regex>
> > int main(int, char ** argv) {
> > std::regex_traits<char>().transform(argv[0], argv[0] + 1);
> > }
>
> > $ clang++ --gcc-toolchain=... -fsanitize=undefined -O2 test.cc
> > /usr/bin/ld: /tmp/test-c112b1.o: in function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::__cxx11::regex_traits<char>::transform<char*>(char*, char*) const':
> > test.cc:(.text._ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_[_ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_]+0x1b): undefined reference to `std::__cxx11::collate<char> const* std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)'
> > clang-15: error: linker command failed with exit code 1 (use -v to see invocation)
That should be present, andis present in my builds:
_ZSt15__try_use_facetINSt7__cxx117collateIcEEEPKT_RKSt6locale
std::__cxx11::collate<char> const*
std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)
version status: compatible
GLIBCXX_3.4.31
type: function
status: added
Was this a clean build, or incremental? I'm guessing the latter.
The makefile deps for libstdc++ don't really support incremental
builds. More precisely, the lack of deps. That symbol should be
defined in src/c++11/cxx11-locale-inst.o which wasn't changed by the
patch, but it includes src/c++11/locale-inst.cc which was changed. So
an incremental rebuild will only rebuild the latter, and so you won't
get the new symbols that should be in the former.
But if you're seeing that with a clean build I'll have to investigate.
On 11/12/22 03:47, Jonathan Wakely wrote:
> On Fri, 11 Nov 2022 at 21:00, Stephan Bergmann <sbergman@redhat.com> wrote:
>>
>> On 11/11/22 06:30, Jonathan Wakely via Gcc-patches wrote:
>>> As discussed in the PR, this makes it three times faster to construct
>>> iostreams objects.
>>>
>>> Tested x86_64-linux. Pushed to trunk.
>>
>> I haven't yet tried to track down what's going on, but with various
>> versions of Clang (e.g. clang-15.0.4-1.fc37.x86_64):
>>
>>> $ cat test.cc
>>> #include <regex>
>>> int main(int, char ** argv) {
>>> std::regex_traits<char>().transform(argv[0], argv[0] + 1);
>>> }
>>
>>> $ clang++ --gcc-toolchain=... -fsanitize=undefined -O2 test.cc
>>> /usr/bin/ld: /tmp/test-c112b1.o: in function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::__cxx11::regex_traits<char>::transform<char*>(char*, char*) const':
>>> test.cc:(.text._ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_[_ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_]+0x1b): undefined reference to `std::__cxx11::collate<char> const* std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)'
>>> clang-15: error: linker command failed with exit code 1 (use -v to see invocation)
>
> That should be present, andis present in my builds:
>
> _ZSt15__try_use_facetINSt7__cxx117collateIcEEEPKT_RKSt6locale
> std::__cxx11::collate<char> const*
> std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)
> version status: compatible
> GLIBCXX_3.4.31
> type: function
> status: added
>
> Was this a clean build, or incremental? I'm guessing the latter.
Yes, indeed. And a full rebuild fixed the issue for me.
Sorry for the noise.
On Sun, 13 Nov 2022, 19:23 Stephan Bergmann via Libstdc++, <
libstdc++@gcc.gnu.org> wrote:
> On 11/12/22 03:47, Jonathan Wakely wrote:
> > On Fri, 11 Nov 2022 at 21:00, Stephan Bergmann <sbergman@redhat.com>
> wrote:
> >>
> >> On 11/11/22 06:30, Jonathan Wakely via Gcc-patches wrote:
> >>> As discussed in the PR, this makes it three times faster to construct
> >>> iostreams objects.
> >>>
> >>> Tested x86_64-linux. Pushed to trunk.
> >>
> >> I haven't yet tried to track down what's going on, but with various
> >> versions of Clang (e.g. clang-15.0.4-1.fc37.x86_64):
> >>
> >>> $ cat test.cc
> >>> #include <regex>
> >>> int main(int, char ** argv) {
> >>> std::regex_traits<char>().transform(argv[0], argv[0] + 1);
> >>> }
> >>
> >>> $ clang++ --gcc-toolchain=... -fsanitize=undefined -O2 test.cc
> >>> /usr/bin/ld: /tmp/test-c112b1.o: in function
> `std::__cxx11::basic_string<char, std::char_traits<char>,
> std::allocator<char> >
> std::__cxx11::regex_traits<char>::transform<char*>(char*, char*) const':
> >>>
> test.cc:(.text._ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_[_ZNKSt7__cxx1112regex_traitsIcE9transformIPcEENS_12basic_stringIcSt11char_traitsIcESaIcEEET_S9_]+0x1b):
> undefined reference to `std::__cxx11::collate<char> const*
> std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)'
> >>> clang-15: error: linker command failed with exit code 1 (use -v to see
> invocation)
> >
> > That should be present, andis present in my builds:
> >
> > _ZSt15__try_use_facetINSt7__cxx117collateIcEEEPKT_RKSt6locale
> > std::__cxx11::collate<char> const*
> > std::__try_use_facet<std::__cxx11::collate<char> >(std::locale const&)
> > version status: compatible
> > GLIBCXX_3.4.31
> > type: function
> > status: added
> >
> > Was this a clean build, or incremental? I'm guessing the latter.
>
> Yes, indeed. And a full rebuild fixed the issue for me.
>
Ah good.
> Sorry for the noise.
>
No problem, you do a good job of keeping us working well with clang.
@@ -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.
@@ -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,
@@ -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())
{
@@ -82,6 +82,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
friend const _Facet&
use_facet(const locale&);
+ template<typename _Facet>
+ friend const _Facet*
+ __try_use_facet(const locale&) _GLIBCXX_NOTHROW;
+
template<typename _Cache>
friend struct __use_cache;
@@ -496,6 +500,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
friend bool
has_facet(const locale&) throw();
+ template<typename _Facet>
+ 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<typename _Facet>
+ friend const _Facet*
+ __try_use_facet(const locale&) _GLIBCXX_NOTHROW;
+
template<typename _Cache>
friend struct __use_cache;
@@ -87,6 +87,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__s2.data(), __s2.data() + __s2.length()) < 0);
}
+ template<typename _Facet>
+ 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<const _Facet*>(__facets[__i])
+
+ _GLIBCXX_STD_FACET(ctype<char>);
+ _GLIBCXX_STD_FACET(num_get<char>);
+ _GLIBCXX_STD_FACET(num_put<char>);
+ _GLIBCXX_STD_FACET(codecvt<char, char, mbstate_t>);
+ _GLIBCXX_STD_FACET(collate<char>);
+ _GLIBCXX_STD_FACET(moneypunct<char>);
+ _GLIBCXX_STD_FACET(moneypunct<char, true>);
+ _GLIBCXX_STD_FACET(money_get<char>);
+ _GLIBCXX_STD_FACET(money_put<char>);
+ _GLIBCXX_STD_FACET(numpunct<char>);
+ _GLIBCXX_STD_FACET(time_get<char>);
+ _GLIBCXX_STD_FACET(time_put<char>);
+ _GLIBCXX_STD_FACET(messages<char>);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ _GLIBCXX_STD_FACET(ctype<wchar_t>);
+ _GLIBCXX_STD_FACET(num_get<wchar_t>);
+ _GLIBCXX_STD_FACET(num_put<wchar_t>);
+ _GLIBCXX_STD_FACET(codecvt<wchar_t, char, mbstate_t>);
+ _GLIBCXX_STD_FACET(collate<wchar_t>);
+ _GLIBCXX_STD_FACET(moneypunct<wchar_t>);
+ _GLIBCXX_STD_FACET(moneypunct<wchar_t, true>);
+ _GLIBCXX_STD_FACET(money_get<wchar_t>);
+ _GLIBCXX_STD_FACET(money_put<wchar_t>);
+ _GLIBCXX_STD_FACET(numpunct<wchar_t>);
+ _GLIBCXX_STD_FACET(time_get<wchar_t>);
+ _GLIBCXX_STD_FACET(time_put<wchar_t>);
+ _GLIBCXX_STD_FACET(messages<wchar_t>);
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+ _GLIBCXX_STD_FACET(codecvt<char8_t, char, mbstate_t>);
+#endif
+#if __cplusplus >= 201103L
+ _GLIBCXX_STD_FACET(codecvt<char16_t, char, mbstate_t>);
+ _GLIBCXX_STD_FACET(codecvt<char32_t, char, mbstate_t>);
+#endif
+
+#undef _GLIBCXX_STD_FACET
+
+ if (__i >= __loc._M_impl->_M_facets_size || !__facets[__i])
+ return 0;
+
+#if __cpp_rtti
+ return dynamic_cast<const _Facet*>(__facets[__i]);
+#else
+ return static_cast<const _Facet*>(__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<typename _Facet>
- 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<const _Facet*>(__facets[__i]));
+#if __cplusplus >= 201103L
+ static_assert(__is_base_of(locale::facet, _Facet),
+ "template argument must be derived from locale::facet");
#else
- && static_cast<const _Facet*>(__facets[__i]));
+ (void) static_cast<const _Facet*>(static_cast<const locale::facet*>(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<typename _Facet>
- 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<const _Facet&>(*__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<const _Facet&>(*__facets[__i]);
+ (void) static_cast<const _Facet*>(static_cast<const locale::facet*>(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<char>;
extern template class collate_byname<char>;
+ extern template
+ const collate<char>*
+ __try_use_facet<collate<char> >(const locale&) _GLIBCXX_NOTHROW;
+
extern template
const collate<char>&
use_facet<collate<char> >(const locale&);
@@ -285,6 +350,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
extern template class collate<wchar_t>;
extern template class collate_byname<wchar_t>;
+ extern template
+ const collate<wchar_t>*
+ __try_use_facet<collate<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
extern template
const collate<wchar_t>&
use_facet<collate<wchar_t> >(const locale&);
@@ -1325,6 +1325,22 @@ _GLIBCXX_END_NAMESPACE_LDBL
extern template class _GLIBCXX_NAMESPACE_LDBL num_put<char>;
extern template class ctype_byname<char>;
+ extern template
+ const ctype<char>*
+ __try_use_facet<ctype<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const numpunct<char>*
+ __try_use_facet<numpunct<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const num_put<char>*
+ __try_use_facet<num_put<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const num_get<char>*
+ __try_use_facet<num_get<char> >(const locale&) _GLIBCXX_NOTHROW;
+
extern template
const ctype<char>&
use_facet<ctype<char> >(const locale&);
@@ -1364,6 +1380,22 @@ _GLIBCXX_END_NAMESPACE_LDBL
extern template class _GLIBCXX_NAMESPACE_LDBL num_put<wchar_t>;
extern template class ctype_byname<wchar_t>;
+ extern template
+ const ctype<wchar_t>*
+ __try_use_facet<ctype<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const numpunct<wchar_t>*
+ __try_use_facet<numpunct<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const num_put<wchar_t>*
+ __try_use_facet<num_put<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const num_get<wchar_t>*
+ __try_use_facet<num_get<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
extern template
const ctype<wchar_t>&
use_facet<ctype<wchar_t> >(const locale&);
@@ -1380,7 +1412,7 @@ _GLIBCXX_END_NAMESPACE_LDBL
const num_get<wchar_t>&
use_facet<num_get<wchar_t> >(const locale&);
- extern template
+ extern template
bool
has_facet<ctype<wchar_t> >(const locale&);
@@ -1691,6 +1691,38 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
extern template class messages<char>;
extern template class messages_byname<char>;
+ extern template
+ const moneypunct<char, true>*
+ __try_use_facet<moneypunct<char, true> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const moneypunct<char, false>*
+ __try_use_facet<moneypunct<char, false> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const money_put<char>*
+ __try_use_facet<money_put<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const money_get<char>*
+ __try_use_facet<money_get<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const __timepunct<char>*
+ __try_use_facet<__timepunct<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const time_put<char>*
+ __try_use_facet<time_put<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const time_get<char>*
+ __try_use_facet<time_get<char> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const messages<char>*
+ __try_use_facet<messages<char> >(const locale&) _GLIBCXX_NOTHROW;
+
extern template
const moneypunct<char, true>&
use_facet<moneypunct<char, true> >(const locale&);
@@ -1766,6 +1798,38 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
extern template class messages<wchar_t>;
extern template class messages_byname<wchar_t>;
+ extern template
+ const moneypunct<wchar_t, true>*
+ __try_use_facet<moneypunct<wchar_t, true> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const moneypunct<wchar_t, false>*
+ __try_use_facet<moneypunct<wchar_t, false> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const money_put<wchar_t>*
+ __try_use_facet<money_put<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const money_get<wchar_t>*
+ __try_use_facet<money_get<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const __timepunct<wchar_t>*
+ __try_use_facet<__timepunct<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const time_put<wchar_t>*
+ __try_use_facet<time_put<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const time_get<wchar_t>*
+ __try_use_facet<time_get<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
+ extern template
+ const messages<wchar_t>*
+ __try_use_facet<messages<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
+
extern template
const moneypunct<wchar_t, true>&
use_facet<moneypunct<wchar_t, true> >(const locale&);
@@ -32,11 +32,9 @@
namespace std _GLIBCXX_VISIBILITY(default)
{
- template const money_put<C>& use_facet<money_put<C> >(const locale&);
- template const money_get<C>& use_facet<money_get<C> >(const locale&);
-
- template bool has_facet<money_put<C> >(const locale&);
- template bool has_facet<money_get<C> >(const locale&);
+// use_facet and has_facet instantiations
+INSTANTIATE_FACET_ACCESSORS(money_put<C>);
+INSTANTIATE_FACET_ACCESSORS(money_get<C>);
_GLIBCXX_BEGIN_NAMESPACE_LDBL_OR_CXX11
template class money_get<C, istreambuf_iterator<C> >;
@@ -29,11 +29,9 @@
namespace std _GLIBCXX_VISIBILITY(default)
{
#if ! _GLIBCXX_USE_CXX11_ABI
- template const num_get<C>& use_facet<num_get<C> >(const locale&);
- template const num_put<C>& use_facet<num_put<C> >(const locale&);
-
- template bool has_facet<num_get<C> >(const locale&);
- template bool has_facet<num_put<C> >(const locale&);
+// use_facet and has_facet instantiations
+INSTANTIATE_FACET_ACCESSORS(num_get<C>);
+INSTANTIATE_FACET_ACCESSORS(num_put<C>);
#endif
_GLIBCXX_BEGIN_NAMESPACE_LDBL
@@ -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<C>;
_GLIBCXX_END_NAMESPACE_CXX11
- // use_facet
+// use_facet and has_facet instantiations
#if ! _GLIBCXX_USE_CXX11_ABI
- template
- const ctype<C>&
- use_facet<ctype<C> >(const locale&);
-
- template
- const codecvt<C, char, mbstate_t>&
- use_facet<codecvt<C, char, mbstate_t> >(const locale&);
+INSTANTIATE_FACET_ACCESSORS(ctype<C>);
+INSTANTIATE_FACET_ACCESSORS(codecvt<C, char, mbstate_t>);
#endif
-
- template
- const collate<C>&
- use_facet<collate<C> >(const locale&);
-
- template
- const numpunct<C>&
- use_facet<numpunct<C> >(const locale&);
-
- template
- const moneypunct<C, true>&
- use_facet<moneypunct<C, true> >(const locale&);
-
- template
- const moneypunct<C, false>&
- use_facet<moneypunct<C, false> >(const locale&);
-
+INSTANTIATE_FACET_ACCESSORS(collate<C>);
+INSTANTIATE_FACET_ACCESSORS(numpunct<C>);
+INSTANTIATE_FACET_ACCESSORS(moneypunct<C, false>);
+// No explicit instantiation of has_facet<moneypunct<C, true>> for some reason.
+INSTANTIATE_USE_FACET (moneypunct<C, true>);
#if ! _GLIBCXX_USE_CXX11_ABI
- template
- const __timepunct<C>&
- use_facet<__timepunct<C> >(const locale&);
-
- template
- const time_put<C>&
- use_facet<time_put<C> >(const locale&);
+INSTANTIATE_FACET_ACCESSORS(__timepunct<C>);
+INSTANTIATE_FACET_ACCESSORS(time_put<C>);
#endif
-
- template
- const time_get<C>&
- use_facet<time_get<C> >(const locale&);
-
- template
- const messages<C>&
- use_facet<messages<C> >(const locale&);
-
- // has_facet
-#if ! _GLIBCXX_USE_CXX11_ABI
- template
- bool
- has_facet<ctype<C> >(const locale&);
-
- template
- bool
- has_facet<codecvt<C, char, mbstate_t> >(const locale&);
-#endif
-
- template
- bool
- has_facet<collate<C> >(const locale&);
-
- template
- bool
- has_facet<numpunct<C> >(const locale&);
-
- template
- bool
- has_facet<moneypunct<C> >(const locale&);
-
-#if ! _GLIBCXX_USE_CXX11_ABI
- template
- bool
- has_facet<__timepunct<C> >(const locale&);
-
- template
- bool
- has_facet<time_put<C> >(const locale&);
-#endif
-
- template
- bool
- has_facet<time_get<C> >(const locale&);
-
- template
- bool
- has_facet<messages<C> >(const locale&);
-
+INSTANTIATE_FACET_ACCESSORS(time_get<C>);
+INSTANTIATE_FACET_ACCESSORS(messages<C>);
#if ! _GLIBCXX_USE_CXX11_ABI
// locale functions.
@@ -48,6 +48,10 @@ namespace std _GLIBCXX_VISIBILITY(default)
template bool has_facet<num_get<C> >(const locale&);
template bool has_facet<money_put<C> >(const locale&);
template bool has_facet<money_get<C> >(const locale&);
+ template const num_put<C>* __try_use_facet<num_put<C> >(const locale&);
+ template const num_get<C>* __try_use_facet<num_get<C> >(const locale&);
+ template const money_put<C>* __try_use_facet<money_put<C> >(const locale&);
+ template const money_get<C>* __try_use_facet<money_get<C> >(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<num_get<C> >(const locale&);
template bool has_facet<money_put<C> >(const locale&);
template bool has_facet<money_get<C> >(const locale&);
+ template const num_put<C>* __try_use_facet<num_put<C> >(const locale&);
+ template const num_get<C>* __try_use_facet<num_get<C> >(const locale&);
+ template const money_put<C>* __try_use_facet<money_put<C> >(const locale&);
+ template const money_get<C>* __try_use_facet<money_get<C> >(const locale&);
#undef C
#endif
}
@@ -17,14 +17,15 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { 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 <locale>
template <class Char, int I>
struct trait: std::char_traits<Char> {};
+// Generates unique types so we get distinct diagnostics for each line.
template <class Char, int I>
std::basic_string<Char, trait<Char, I> > make_str()
{