1// Locale support -*- C++ -*-
2
3// Copyright (C) 2014-2020 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25//
26// ISO C++ 14882: 22.1  Locales
27//
28
29// This file defines classes that behave like the standard predefined locale
30// facets (collate, money_get etc.) except that they forward all virtual
31// functions to another facet which uses a different std::string ABI,
32// converting between string types as needed.
33// When a user replaces one of the relevant facets the corresponding shim in
34// this file is used so that the replacement facet can be used (via the shim)
35// in code that uses the other std::string ABI from the replacing code.
36
37#ifndef _GLIBCXX_USE_CXX11_ABI
38# define _GLIBCXX_USE_CXX11_ABI 1
39#endif
40#include <locale>
41
42#if ! _GLIBCXX_USE_DUAL_ABI
43# error This file should not be compiled for this configuration.
44#endif
45
46namespace std _GLIBCXX_VISIBILITY(default)
47{
48_GLIBCXX_BEGIN_NAMESPACE_VERSION
49
50  // Base class of facet shims, holds a reference to the underlying facet
51  // that the shim forwards to.
52  class locale::facet::__shim
53  {
54  public:
55    const facet* _M_get() const { return _M_facet; }
56
57    __shim(const __shim&) = delete;
58    __shim& operator=(const __shim&) = delete;
59
60  protected:
61    explicit
62    __shim(const facet* __f) : _M_facet(__f) { __f->_M_add_reference(); }
63
64    ~__shim() { _M_facet->_M_remove_reference(); }
65
66  private:
67    const facet* _M_facet;
68  };
69
70namespace __facet_shims
71{
72  namespace // unnamed
73  {
74    template<typename C>
75      void __destroy_string(void* p)
76      {
77	static_cast<std::basic_string<C>*>(p)->~basic_string();
78      }
79  } // namespace
80
81  // Manages a buffer of uninitialized memory that can store a std::string
82  // or std::wstring, using either ABI, and convert to the other ABI.
83  class __any_string
84  {
85    struct __attribute__((may_alias)) __str_rep
86    {
87      union {
88	const void* _M_p;
89	char* _M_pc;
90#ifdef _GLIBCXX_USE_WCHAR_T
91	wchar_t* _M_pwc;
92#endif
93      };
94      size_t _M_len;
95      char _M_unused[16];
96
97      operator const char*() const { return _M_pc; }
98#ifdef _GLIBCXX_USE_WCHAR_T
99      operator const wchar_t*() const { return _M_pwc; }
100#endif
101    };
102    union {
103      __str_rep _M_str;
104      char _M_bytes[sizeof(__str_rep)];
105    };
106    using __dtor_func = void(*)(void*);
107    __dtor_func _M_dtor = nullptr;
108
109#if _GLIBCXX_USE_CXX11_ABI
110    // SSO strings overlay the entire __str_rep structure.
111    static_assert(sizeof(std::string) == sizeof(__str_rep),
112		  "std::string changed size!");
113#else
114    // COW strings overlay just the pointer, the length is stored manually.
115    static_assert(sizeof(std::string) == sizeof(__str_rep::_M_p),
116		  "std::string changed size!");
117#endif
118# ifdef _GLIBCXX_USE_WCHAR_T
119    static_assert(sizeof(std::wstring) == sizeof(std::string),
120		  "std::wstring and std::string are different sizes!");
121# endif
122
123  public:
124    __any_string() = default;
125    ~__any_string() { if (_M_dtor) _M_dtor(_M_bytes); }
126
127    __any_string(const __any_string&) = delete;
128    __any_string& operator=(const __any_string&) = delete;
129
130    // Store a string (and its length if needed) in the buffer and
131    // set _M_dtor to the function that runs the right destructor.
132    template<typename C>
133      __any_string&
134      operator=(const basic_string<C>& s)
135      {
136	if (_M_dtor)
137	  _M_dtor(_M_bytes);
138	::new(_M_bytes) basic_string<C>(s);
139#if ! _GLIBCXX_USE_CXX11_ABI
140	_M_str._M_len = s.length();
141#endif
142	_M_dtor = __destroy_string<C>;
143	return *this;
144      }
145
146    // Create a new string with a copy of the characters in the stored string.
147    // The returned object will match the caller's string ABI, even when the
148    // stored string doesn't.
149    template<typename C>
150      _GLIBCXX_DEFAULT_ABI_TAG
151      operator basic_string<C>() const
152      {
153	if (!_M_dtor)
154	  __throw_logic_error("uninitialized __any_string");
155	return basic_string<C>(static_cast<const C*>(_M_str), _M_str._M_len);
156      }
157  };
158
159  // This file is compiled twice, with and without this macro defined.
160  // Define tag types to distinguish between the two cases and to allow
161  // overloading on the tag.
162  using current_abi = __bool_constant<_GLIBCXX_USE_CXX11_ABI>;
163  using other_abi = __bool_constant<!_GLIBCXX_USE_CXX11_ABI>;
164
165  using facet = locale::facet;
166
167  // Declare the functions that shims defined in this file will call to
168  // perform work in the context of the other ABI.
169  // These will be defined when this file is recompiled for the other ABI
170  // (at which point what is now "current_abi" will become "other_abi").
171
172  template<typename C>
173    void
174    __numpunct_fill_cache(other_abi, const facet*, __numpunct_cache<C>*);
175
176  template<typename C>
177    int
178    __collate_compare(other_abi, const facet*, const C*, const C*,
179		      const C*, const C*);
180
181  template<typename C>
182    void
183    __collate_transform(other_abi, const facet*, __any_string&,
184			const C*, const C*);
185
186  template<typename C>
187    time_base::dateorder
188    __time_get_dateorder(other_abi, const facet* f);
189
190  template<typename C>
191    istreambuf_iterator<C>
192    __time_get(other_abi, const facet* f,
193	       istreambuf_iterator<C> beg, istreambuf_iterator<C> end,
194	       ios_base& io, ios_base::iostate& err, tm* t, char which);
195
196  template<typename C, bool Intl>
197    void
198    __moneypunct_fill_cache(other_abi, const facet*,
199			    __moneypunct_cache<C, Intl>*);
200
201  template<typename C>
202    istreambuf_iterator<C>
203    __money_get(other_abi, const facet*,
204		istreambuf_iterator<C>, istreambuf_iterator<C>,
205		bool, ios_base&, ios_base::iostate&,
206		long double*, __any_string*);
207
208  template<typename C>
209    ostreambuf_iterator<C>
210    __money_put(other_abi, const facet*, ostreambuf_iterator<C>, bool,
211		ios_base&, C, long double, const __any_string*);
212
213  template<typename C>
214    messages_base::catalog
215    __messages_open(other_abi, const facet*, const char*, size_t,
216		    const locale&);
217
218  template<typename C>
219    void
220    __messages_get(other_abi, const facet*, __any_string&,
221		   messages_base::catalog, int, int, const C*, size_t);
222
223  template<typename C>
224    void
225    __messages_close(other_abi, const facet*, messages_base::catalog);
226
227#pragma GCC diagnostic push
228// Suppress -Wabi=2 warnings due to empty struct argument passing changes.
229// TODO This should use -Wabi=12 but that currently fails (PR c++/87611).
230#pragma GCC diagnostic ignored "-Wabi"
231
232  namespace // unnamed
233  {
234    struct __shim_accessor : facet
235    {
236      using facet::__shim;  // Redeclare protected member as public.
237    };
238    using __shim = __shim_accessor::__shim;
239
240    template<typename _CharT>
241      struct numpunct_shim : std::numpunct<_CharT>, __shim
242      {
243	typedef typename numpunct<_CharT>::__cache_type __cache_type;
244
245	// f must point to a type derived from numpunct<C>[abi:other]
246	numpunct_shim(const facet* f, __cache_type* c = new __cache_type)
247	: std::numpunct<_CharT>(c), __shim(f), _M_cache(c)
248	{
249	  __numpunct_fill_cache(other_abi{}, f, c);
250	}
251
252	~numpunct_shim()
253	{
254	  // Stop GNU locale's ~numpunct() from freeing the cached string.
255	  _M_cache->_M_grouping_size = 0;
256	}
257
258	// No need to override any virtual functions, the base definitions
259	// will return the cached data.
260
261	__cache_type* _M_cache;
262      };
263
264    template<typename _CharT>
265      struct collate_shim : std::collate<_CharT>, __shim
266      {
267	typedef basic_string<_CharT>	string_type;
268
269	// f must point to a type derived from collate<C>[abi:other]
270	collate_shim(const facet* f) : __shim(f) { }
271
272	virtual int
273	do_compare(const _CharT* lo1, const _CharT* hi1,
274		   const _CharT* lo2, const _CharT* hi2) const
275	{
276	  return __collate_compare(other_abi{}, _M_get(),
277				   lo1, hi1, lo2, hi2);
278	}
279
280	virtual string_type
281	do_transform(const _CharT* lo, const _CharT* hi) const
282	{
283	  __any_string st;
284	  __collate_transform(other_abi{}, _M_get(), st, lo, hi);
285	  return st;
286	}
287      };
288
289    template<typename _CharT>
290      struct time_get_shim : std::time_get<_CharT>, __shim
291      {
292	typedef typename std::time_get<_CharT>::iter_type iter_type;
293	typedef typename std::time_get<_CharT>::char_type char_type;
294
295	// f must point to a type derived from time_get<C>[abi:other]
296	time_get_shim(const facet* f) : __shim(f) { }
297
298	virtual time_base::dateorder
299	do_date_order() const
300	{ return __time_get_dateorder<_CharT>(other_abi{}, _M_get()); }
301
302	virtual iter_type
303	do_get_time(iter_type beg, iter_type end, ios_base& io,
304		    ios_base::iostate& err, tm* t) const
305	{
306	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
307			    't');
308	}
309
310	virtual iter_type
311	do_get_date(iter_type beg, iter_type end, ios_base& io,
312		    ios_base::iostate& err, tm* t) const
313	{
314	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
315			    'd');
316	}
317
318	virtual iter_type
319	do_get_weekday(iter_type beg, iter_type end, ios_base& io,
320		       ios_base::iostate& err, tm* t) const
321	{
322	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
323			    'w');
324	}
325
326	virtual iter_type
327	do_get_monthname(iter_type beg, iter_type end, ios_base& io,
328			 ios_base::iostate& err, tm* t) const
329	{
330	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
331			    'm');
332	}
333
334	virtual iter_type
335	do_get_year(iter_type beg, iter_type end, ios_base& io,
336		    ios_base::iostate& err, tm* t) const
337	{
338	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
339			    'y');
340	}
341      };
342
343    template<typename _CharT, bool _Intl>
344      struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, __shim
345      {
346	typedef typename moneypunct<_CharT, _Intl>::__cache_type __cache_type;
347
348	// f must point to a type derived from moneypunct<C>[abi:other]
349	moneypunct_shim(const facet* f, __cache_type* c = new __cache_type)
350	: std::moneypunct<_CharT, _Intl>(c), __shim(f), _M_cache(c)
351	{
352	  __moneypunct_fill_cache(other_abi{}, f, c);
353	}
354
355	~moneypunct_shim()
356	{
357	  // Stop GNU locale's ~moneypunct() from freeing the cached strings.
358	  _M_cache->_M_grouping_size = 0;
359	  _M_cache->_M_curr_symbol_size = 0;
360	  _M_cache->_M_positive_sign_size = 0;
361	  _M_cache->_M_negative_sign_size = 0;
362	}
363
364	// No need to override any virtual functions, the base definitions
365	// will return the cached data.
366
367	__cache_type* _M_cache;
368      };
369
370    template<typename _CharT>
371      struct money_get_shim : std::money_get<_CharT>, __shim
372      {
373	typedef typename std::money_get<_CharT>::iter_type iter_type;
374	typedef typename std::money_get<_CharT>::char_type char_type;
375	typedef typename std::money_get<_CharT>::string_type string_type;
376
377	// f must point to a type derived from money_get<C>[abi:other]
378	money_get_shim(const facet* f) : __shim(f) { }
379
380	virtual iter_type
381	do_get(iter_type s, iter_type end, bool intl, ios_base& io,
382	       ios_base::iostate& err, long double& units) const
383	{
384	  ios_base::iostate err2 = ios_base::goodbit;
385	  long double units2;
386	  s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2,
387			  &units2, nullptr);
388	  if (err2 == ios_base::goodbit)
389	    units = units2;
390	  else
391	    err = err2;
392	  return s;
393	}
394
395	virtual iter_type
396	do_get(iter_type s, iter_type end, bool intl, ios_base& io,
397	       ios_base::iostate& err, string_type& digits) const
398	{
399	  __any_string st;
400	  ios_base::iostate err2 = ios_base::goodbit;
401	  s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2,
402			  nullptr, &st);
403	  if (err2 == ios_base::goodbit)
404	    digits = st;
405	  else
406	    err = err2;
407	  return s;
408	}
409      };
410
411    template<typename _CharT>
412      struct money_put_shim : std::money_put<_CharT>, __shim
413      {
414	typedef typename std::money_put<_CharT>::iter_type iter_type;
415	typedef typename std::money_put<_CharT>::char_type char_type;
416	typedef typename std::money_put<_CharT>::string_type string_type;
417
418	// f must point to a type derived from money_put<C>[abi:other]
419	money_put_shim(const facet* f) : __shim(f) { }
420
421	virtual iter_type
422	do_put(iter_type s, bool intl, ios_base& io,
423	       char_type fill, long double units) const
424	{
425	  return __money_put(other_abi{}, _M_get(), s, intl, io, fill, units,
426			     nullptr);
427	}
428
429	virtual iter_type
430	do_put(iter_type s, bool intl, ios_base& io,
431	       char_type fill, const string_type& digits) const
432	{
433	  __any_string st;
434	  st = digits;
435	  return __money_put(other_abi{}, _M_get(), s, intl, io, fill, 0.L,
436			     &st);
437	}
438      };
439
440    template<typename _CharT>
441      struct messages_shim : std::messages<_CharT>, __shim
442      {
443	typedef messages_base::catalog  catalog;
444	typedef basic_string<_CharT>	string_type;
445
446	// f must point to a type derived from messages<C>[abi:other]
447	messages_shim(const facet* f) : __shim(f) { }
448
449	virtual catalog
450	do_open(const basic_string<char>& s, const locale& l) const
451	{
452	  return __messages_open<_CharT>(other_abi{}, _M_get(),
453					 s.c_str(), s.size(), l);
454	}
455
456	virtual string_type
457	do_get(catalog c, int set, int msgid, const string_type& dfault) const
458	{
459	  __any_string st;
460	  __messages_get(other_abi{}, _M_get(), st, c, set, msgid,
461			 dfault.c_str(), dfault.size());
462	  return st;
463	}
464
465	virtual void
466	do_close(catalog c) const
467	{
468	  __messages_close<_CharT>(other_abi{}, _M_get(), c);
469	}
470      };
471
472    template class numpunct_shim<char>;
473    template class collate_shim<char>;
474    template class moneypunct_shim<char, true>;
475    template class moneypunct_shim<char, false>;
476    template class money_get_shim<char>;
477    template class money_put_shim<char>;
478    template class messages_shim<char>;
479#ifdef _GLIBCXX_USE_WCHAR_T
480    template class numpunct_shim<wchar_t>;
481    template class collate_shim<wchar_t>;
482    template class moneypunct_shim<wchar_t, true>;
483    template class moneypunct_shim<wchar_t, false>;
484    template class money_get_shim<wchar_t>;
485    template class money_put_shim<wchar_t>;
486    template class messages_shim<wchar_t>;
487#endif
488
489    template<typename C>
490      inline size_t
491      __copy(const C*& dest, const basic_string<C>& s)
492      {
493	auto len = s.length();
494	C* p = new C[len+1];
495	s.copy(p, len);
496	p[len] = '\0';
497	dest = p;
498	return len;
499      }
500
501  } // namespace
502
503  // Now define and instantiate the functions that will be called by the
504  // shim facets defined when this file is recompiled for the other ABI.
505
506  // Cache the values returned by the numpunct facet f.
507  // Sets c->_M_allocated so that the __numpunct_cache destructor will
508  // delete[] the strings allocated by this function.
509  template<typename C>
510    void
511    __numpunct_fill_cache(current_abi, const facet* f, __numpunct_cache<C>* c)
512    {
513      auto* m = static_cast<const numpunct<C>*>(f);
514
515      c->_M_decimal_point = m->decimal_point();
516      c->_M_thousands_sep = m->thousands_sep();
517
518      c->_M_grouping = nullptr;
519      c->_M_truename = nullptr;
520      c->_M_falsename = nullptr;
521      // set _M_allocated so that if any allocation fails the previously
522      // allocated strings will be deleted in ~__numpunct_cache()
523      c->_M_allocated = true;
524
525      c->_M_grouping_size = __copy(c->_M_grouping, m->grouping());
526      c->_M_truename_size = __copy(c->_M_truename, m->truename());
527      c->_M_falsename_size = __copy(c->_M_falsename, m->falsename());
528    }
529
530  template void
531  __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<char>*);
532
533#ifdef _GLIBCXX_USE_WCHAR_T
534  template void
535  __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<wchar_t>*);
536#endif
537
538  template<typename C>
539    int
540    __collate_compare(current_abi, const facet* f, const C* lo1, const C* hi1,
541		      const C* lo2, const C* hi2)
542    {
543      return static_cast<const collate<C>*>(f)->compare(lo1, hi1, lo2, hi2);
544    }
545
546  template int
547  __collate_compare(current_abi, const facet*, const char*, const char*,
548		    const char*, const char*);
549
550#ifdef _GLIBCXX_USE_WCHAR_T
551  template int
552  __collate_compare(current_abi, const facet*, const wchar_t*, const wchar_t*,
553		    const wchar_t*, const wchar_t*);
554#endif
555
556  template<typename C>
557    void
558    __collate_transform(current_abi, const facet* f, __any_string& st,
559			const C* __lo, const C* __hi)
560    {
561      auto* c = static_cast<const collate<C>*>(f);
562      st = c->transform(__lo, __hi);
563    }
564
565  template void
566  __collate_transform(current_abi, const facet*, __any_string&,
567		      const char*, const char*);
568
569#ifdef _GLIBCXX_USE_WCHAR_T
570  template void
571  __collate_transform(current_abi, const facet*, __any_string&,
572		      const wchar_t*, const wchar_t*);
573#endif
574
575  // Cache the values returned by the moneypunct facet, f.
576  // Sets c->_M_allocated so that the __moneypunct_cache destructor will
577  // delete[] the strings allocated by this function.
578  template<typename C, bool Intl>
579    void
580    __moneypunct_fill_cache(current_abi, const facet* f,
581			    __moneypunct_cache<C, Intl>* c)
582    {
583      auto* m = static_cast<const moneypunct<C, Intl>*>(f);
584
585      c->_M_decimal_point = m->decimal_point();
586      c->_M_thousands_sep = m->thousands_sep();
587      c->_M_frac_digits = m->frac_digits();
588
589      c->_M_grouping = nullptr;
590      c->_M_curr_symbol = nullptr;
591      c->_M_positive_sign = nullptr;
592      c->_M_negative_sign = nullptr;
593      // Set _M_allocated so that if any allocation fails the previously
594      // allocated strings will be deleted in ~__moneypunct_cache().
595      c->_M_allocated = true;
596
597      c->_M_grouping_size = __copy(c->_M_grouping, m->grouping());
598      c->_M_curr_symbol_size = __copy(c->_M_curr_symbol, m->curr_symbol());
599      c->_M_positive_sign_size
600	= __copy(c->_M_positive_sign, m->positive_sign());
601      c->_M_negative_sign_size
602	= __copy(c->_M_negative_sign, m->negative_sign());
603
604      c->_M_pos_format = m->pos_format();
605      c->_M_neg_format = m->neg_format();
606    }
607
608  template void
609  __moneypunct_fill_cache(current_abi, const facet*,
610			  __moneypunct_cache<char, true>*);
611
612  template void
613  __moneypunct_fill_cache(current_abi, const facet*,
614			  __moneypunct_cache<char, false>*);
615
616#ifdef _GLIBCXX_USE_WCHAR_T
617  template void
618  __moneypunct_fill_cache(current_abi, const facet*,
619			  __moneypunct_cache<wchar_t, true>*);
620
621  template void
622  __moneypunct_fill_cache(current_abi, const facet*,
623			  __moneypunct_cache<wchar_t, false>*);
624#endif
625
626  template<typename C>
627    messages_base::catalog
628    __messages_open(current_abi, const facet* f, const char* s, size_t n,
629		    const locale& l)
630    {
631      auto* m = static_cast<const messages<C>*>(f);
632      string str(s, n);
633      return m->open(str, l);
634    }
635
636  template messages_base::catalog
637  __messages_open<char>(current_abi, const facet*, const char*, size_t,
638			const locale&);
639
640#ifdef _GLIBCXX_USE_WCHAR_T
641  template messages_base::catalog
642  __messages_open<wchar_t>(current_abi, const facet*, const char*, size_t,
643			   const locale&);
644#endif
645
646  template<typename C>
647    void
648    __messages_get(current_abi, const facet* f, __any_string& st,
649		   messages_base::catalog c, int set, int msgid,
650		   const C* s, size_t n)
651    {
652      auto* m = static_cast<const messages<C>*>(f);
653      st = m->get(c, set, msgid, basic_string<C>(s, n));
654    }
655
656  template void
657  __messages_get(current_abi, const facet*, __any_string&,
658		 messages_base::catalog, int, int, const char*, size_t);
659
660#ifdef _GLIBCXX_USE_WCHAR_T
661  template void
662  __messages_get(current_abi, const facet*, __any_string&,
663		 messages_base::catalog, int, int, const wchar_t*, size_t);
664#endif
665
666  template<typename C>
667    void
668    __messages_close(current_abi, const facet* f, messages_base::catalog c)
669    {
670      static_cast<const messages<C>*>(f)->close(c);
671    }
672
673  template void
674  __messages_close<char>(current_abi, const facet*, messages_base::catalog c);
675
676#ifdef _GLIBCXX_USE_WCHAR_T
677  template void
678  __messages_close<wchar_t>(current_abi, const facet*,
679			    messages_base::catalog c);
680#endif
681
682  template<typename C>
683    time_base::dateorder
684    __time_get_dateorder(current_abi, const facet* f)
685    { return static_cast<const time_get<C>*>(f)->date_order(); }
686
687  template time_base::dateorder
688  __time_get_dateorder<char>(current_abi, const facet*);
689
690#ifdef _GLIBCXX_USE_WCHAR_T
691  template time_base::dateorder
692  __time_get_dateorder<wchar_t>(current_abi, const facet*);
693#endif
694
695  template<typename C>
696    istreambuf_iterator<C>
697    __time_get(current_abi, const facet* f,
698	       istreambuf_iterator<C> beg, istreambuf_iterator<C> end,
699	       ios_base& io, ios_base::iostate& err, tm* t, char which)
700    {
701      auto* g = static_cast<const time_get<C>*>(f);
702      switch(which)
703      {
704      case 't':
705	return g->get_time(beg, end, io, err, t);
706      case 'd':
707	return g->get_date(beg, end, io, err, t);
708      case 'w':
709	return g->get_weekday(beg, end, io, err, t);
710      case 'm':
711	return g->get_monthname(beg, end, io, err, t);
712      case 'y':
713	return g->get_year(beg, end, io, err, t);
714      default:
715	__builtin_unreachable();
716      }
717    }
718
719  template istreambuf_iterator<char>
720  __time_get(current_abi, const facet*,
721	     istreambuf_iterator<char>, istreambuf_iterator<char>,
722	     ios_base&, ios_base::iostate&, tm*, char);
723
724#ifdef _GLIBCXX_USE_WCHAR_T
725  template istreambuf_iterator<wchar_t>
726  __time_get(current_abi, const facet*,
727	     istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>,
728	     ios_base&, ios_base::iostate&, tm*, char);
729#endif
730
731  template<typename C>
732    istreambuf_iterator<C>
733    __money_get(current_abi, const facet* f,
734		istreambuf_iterator<C> s, istreambuf_iterator<C> end,
735		bool intl, ios_base& str, ios_base::iostate& err,
736		long double* units, __any_string* digits)
737    {
738      auto* m = static_cast<const money_get<C>*>(f);
739      if (units)
740	return m->get(s, end, intl, str, err, *units);
741      basic_string<C> digits2;
742      s = m->get(s, end, intl, str, err, digits2);
743      if (err == ios_base::goodbit)
744	*digits = digits2;
745      return s;
746    }
747
748  template istreambuf_iterator<char>
749  __money_get(current_abi, const facet*,
750	      istreambuf_iterator<char>, istreambuf_iterator<char>,
751	      bool, ios_base&, ios_base::iostate&,
752	      long double*, __any_string*);
753
754#ifdef _GLIBCXX_USE_WCHAR_T
755  template istreambuf_iterator<wchar_t>
756  __money_get(current_abi, const facet*,
757	      istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>,
758	      bool, ios_base&, ios_base::iostate&,
759	      long double*, __any_string*);
760#endif
761
762  template<typename C>
763    ostreambuf_iterator<C>
764    __money_put(current_abi, const facet* f, ostreambuf_iterator<C> s,
765		bool intl, ios_base& io, C fill, long double units,
766		const __any_string* digits)
767    {
768      auto* m = static_cast<const money_put<C>*>(f);
769      if (digits)
770	return m->put(s, intl, io, fill, *digits);
771      else
772	return m->put(s, intl, io, fill, units);
773    }
774
775#pragma GCC diagnostic pop
776
777  template ostreambuf_iterator<char>
778  __money_put(current_abi, const facet*, ostreambuf_iterator<char>,
779		bool, ios_base&, char, long double, const __any_string*);
780
781#ifdef _GLIBCXX_USE_WCHAR_T
782  template ostreambuf_iterator<wchar_t>
783  __money_put(current_abi, const facet*, ostreambuf_iterator<wchar_t>,
784		bool, ios_base&, wchar_t, long double, const __any_string*);
785#endif
786
787} // namespace __facet_shims
788
789  // Create a new shim facet of type WHICH that forwards calls to F.
790  // F is the replacement facet provided by the user, WHICH is the ID of
791  // F's "other ABI twin" which we are replacing with a shim.
792  const locale::facet*
793#if _GLIBCXX_USE_CXX11_ABI
794  locale::facet::_M_sso_shim(const locale::id* which) const
795#else
796  locale::facet::_M_cow_shim(const locale::id* which) const
797#endif
798  {
799    using namespace __facet_shims;
800
801#if __cpp_rtti
802    // If this is already a shim just use its underlying facet.
803    if (auto* p = dynamic_cast<const __shim*>(this))
804      return p->_M_get();
805#endif
806
807    if (which == &numpunct<char>::id)
808      return new numpunct_shim<char>{this};
809    if (which == &std::collate<char>::id)
810      return new collate_shim<char>{this};
811    if (which == &time_get<char>::id)
812      return new time_get_shim<char>{this};
813    if (which == &money_get<char>::id)
814      return new money_get_shim<char>{this};
815    if (which == &money_put<char>::id)
816      return new money_put_shim<char>{this};
817    if (which == &moneypunct<char, true>::id)
818      return new moneypunct_shim<char, true>{this};
819    if (which == &moneypunct<char, false>::id)
820      return new moneypunct_shim<char, false>{this};
821    if (which == &std::messages<char>::id)
822      return new messages_shim<char>{this};
823#ifdef _GLIBCXX_USE_WCHAR_T
824    if (which == &numpunct<wchar_t>::id)
825      return new numpunct_shim<wchar_t>{this};
826    if (which == &std::collate<wchar_t>::id)
827      return new collate_shim<wchar_t>{this};
828    if (which == &time_get<wchar_t>::id)
829      return new time_get_shim<wchar_t>{this};
830    if (which == &money_get<wchar_t>::id)
831      return new money_get_shim<wchar_t>{this};
832    if (which == &money_put<wchar_t>::id)
833      return new money_put_shim<wchar_t>{this};
834    if (which == &moneypunct<wchar_t, true>::id)
835      return new moneypunct_shim<wchar_t, true>{this};
836    if (which == &moneypunct<wchar_t, false>::id)
837      return new moneypunct_shim<wchar_t, false>{this};
838    if (which == &std::messages<wchar_t>::id)
839      return new messages_shim<wchar_t>{this};
840#endif
841    __throw_logic_error("cannot create shim for unknown locale::facet");
842  }
843
844_GLIBCXX_END_NAMESPACE_VERSION
845} // namespace std
846