]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Avoid redundant checks in std::use_facet [PR103755]
authorJonathan Wakely <jwakely@redhat.com>
Wed, 9 Nov 2022 21:44:31 +0000 (21:44 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Fri, 11 Nov 2022 04:00:58 +0000 (04:00 +0000)
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.

12 files changed:
libstdc++-v3/config/abi/pre/gnu.ver
libstdc++-v3/include/bits/basic_ios.tcc
libstdc++-v3/include/bits/fstream.tcc
libstdc++-v3/include/bits/locale_classes.h
libstdc++-v3/include/bits/locale_classes.tcc
libstdc++-v3/include/bits/locale_facets.tcc
libstdc++-v3/include/bits/locale_facets_nonio.tcc
libstdc++-v3/src/c++11/locale-inst-monetary.h
libstdc++-v3/src/c++11/locale-inst-numeric.h
libstdc++-v3/src/c++11/locale-inst.cc
libstdc++-v3/src/c++98/compatibility-ldbl.cc
libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc

index 4d97ec371478f5cceaad844b3819ce8c387e3822..225d6dc482b5515cd8d31fc9400ac3d09cd9636f 100644 (file)
@@ -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.
index 2bbcdc20dc0bbfe4579228162955c40fc38b9194..15d35a46cf4e22973a268c7f9c1dc08b36b24c9f 100644 (file)
@@ -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,
index 2e936962837190b359ee736719a487a4b6a16f03..8158ab30312541916834c81f1dba42a2d7ddf3ad 100644 (file)
@@ -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())
        {
index 6cad0ff565576fa4191cb43aca2e3e3f63b4985a..6912a54d607b9f364a7b58f4c9f17d8d92f7dfd2 100644 (file)
@@ -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;
 
index 9cc4f238ee768c1a36ca0f6fdabeee9eb22be519..7a67f5cd31517574da8515fab7a3bbd897d79ba0 100644 (file)
@@ -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&);
index ec7cce4a64043f71c1b849415af375af72b021d1..dd5c45e223b2c42c651e6885a73795c89c32d476 100644 (file)
@@ -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&);
 
index 17a2c8d4486e8fe295d72d613dd3979d471afca5..320bcf222068d8240d7f2ab1c41f40c8770a0c3a 100644 (file)
@@ -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&);
index e1c696dc4e3d97bc95e112183b25a159ad55dee9..ff8439857d2e8985dd2355c95af0e64d51058e66 100644 (file)
 
 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> >;
index 1417ac25ed4631a801746b34e1779bfe7e1cafff..4b970f75f6ef3b76607fc3a5a31922caa21be6cf 100644 (file)
 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
index 3aee5df9b040fbc956b22f20c5678f0d3e08331e..b264cb381ec1987abaf0a40e48dddc5eee8028a0 100644 (file)
 # 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
-#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&);
-#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&);
-
-#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&);
-#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
+// use_facet and has_facet instantiations
 #if ! _GLIBCXX_USE_CXX11_ABI
-  template
-    bool
-    has_facet<ctype<C> >(const locale&);
-
-  template
-    bool
-    has_facet<codecvt<C, char, mbstate_t> >(const locale&);
+INSTANTIATE_FACET_ACCESSORS(ctype<C>);
+INSTANTIATE_FACET_ACCESSORS(codecvt<C, char, mbstate_t>);
 #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&);
-
+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
-    bool
-    has_facet<__timepunct<C> >(const locale&);
-
-  template
-    bool
-    has_facet<time_put<C> >(const locale&);
+INSTANTIATE_FACET_ACCESSORS(__timepunct<C>);
+INSTANTIATE_FACET_ACCESSORS(time_put<C>);
 #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.
index 683f7a8429ce7aa0449dec586f62b7a8f169503d..55a594380376393b6b325f78fc2ac654d6adc248 100644 (file)
@@ -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
 }
index 7935c99a96fd44c97a369d93bbec95fe9ff712dd..047df40e1d41e73ff5ec6e98b757ce20c7763a1d 100644 (file)
 // 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()
 {