1 // Locale support -*- C++ -*-
2 
3 // Copyright (C) 2014-2019 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 
46 namespace 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:
_M_get() const55     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
__shim(const facet * __f)62     __shim(const facet* __f) : _M_facet(__f) { __f->_M_add_reference(); }
63 
~__shim()64     ~__shim() { _M_facet->_M_remove_reference(); }
65 
66   private:
67     const facet* _M_facet;
68   };
69 
70 namespace __facet_shims
71 {
72   namespace // unnamed
73   {
74     template<typename C>
__destroy_string(void * p)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;
~__any_string()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&
operator =(const basic_string<C> & s)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
operator basic_string<C>() const151       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]
numpunct_shimstd::__facet_shims::__anon3a5d188e0411::numpunct_shim246 	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 
~numpunct_shimstd::__facet_shims::__anon3a5d188e0411::numpunct_shim252 	~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]
collate_shimstd::__facet_shims::__anon3a5d188e0411::collate_shim270 	collate_shim(const facet* f) : __shim(f) { }
271 
272 	virtual int
do_comparestd::__facet_shims::__anon3a5d188e0411::collate_shim273 	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
do_transformstd::__facet_shims::__anon3a5d188e0411::collate_shim281 	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]
time_get_shimstd::__facet_shims::__anon3a5d188e0411::time_get_shim296 	time_get_shim(const facet* f) : __shim(f) { }
297 
298 	virtual time_base::dateorder
do_date_orderstd::__facet_shims::__anon3a5d188e0411::time_get_shim299 	do_date_order() const
300 	{ return __time_get_dateorder<_CharT>(other_abi{}, _M_get()); }
301 
302 	virtual iter_type
do_get_timestd::__facet_shims::__anon3a5d188e0411::time_get_shim303 	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
do_get_datestd::__facet_shims::__anon3a5d188e0411::time_get_shim311 	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
do_get_weekdaystd::__facet_shims::__anon3a5d188e0411::time_get_shim319 	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
do_get_monthnamestd::__facet_shims::__anon3a5d188e0411::time_get_shim327 	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
do_get_yearstd::__facet_shims::__anon3a5d188e0411::time_get_shim335 	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]
moneypunct_shimstd::__facet_shims::__anon3a5d188e0411::moneypunct_shim349 	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 
~moneypunct_shimstd::__facet_shims::__anon3a5d188e0411::moneypunct_shim355 	~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]
money_get_shimstd::__facet_shims::__anon3a5d188e0411::money_get_shim378 	money_get_shim(const facet* f) : __shim(f) { }
379 
380 	virtual iter_type
do_getstd::__facet_shims::__anon3a5d188e0411::money_get_shim381 	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
do_getstd::__facet_shims::__anon3a5d188e0411::money_get_shim396 	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]
money_put_shimstd::__facet_shims::__anon3a5d188e0411::money_put_shim419 	money_put_shim(const facet* f) : __shim(f) { }
420 
421 	virtual iter_type
do_putstd::__facet_shims::__anon3a5d188e0411::money_put_shim422 	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
do_putstd::__facet_shims::__anon3a5d188e0411::money_put_shim430 	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]
messages_shimstd::__facet_shims::__anon3a5d188e0411::messages_shim447 	messages_shim(const facet* f) : __shim(f) { }
448 
449 	virtual catalog
do_openstd::__facet_shims::__anon3a5d188e0411::messages_shim450 	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
do_getstd::__facet_shims::__anon3a5d188e0411::messages_shim457 	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
do_closestd::__facet_shims::__anon3a5d188e0411::messages_shim466 	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
__copy(const C * & dest,const basic_string<C> & s)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
__numpunct_fill_cache(current_abi,const facet * f,__numpunct_cache<C> * c)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
__collate_compare(current_abi,const facet * f,const C * lo1,const C * hi1,const C * lo2,const C * hi2)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
__collate_transform(current_abi,const facet * f,__any_string & st,const C * __lo,const C * __hi)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
__moneypunct_fill_cache(current_abi,const facet * f,__moneypunct_cache<C,Intl> * c)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
__messages_open(current_abi,const facet * f,const char * s,size_t n,const locale & l)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
__messages_get(current_abi,const facet * f,__any_string & st,messages_base::catalog c,int set,int msgid,const C * s,size_t n)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
__messages_close(current_abi,const facet * f,messages_base::catalog c)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
__time_get_dateorder(current_abi,const facet * f)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>
__time_get(current_abi,const facet * f,istreambuf_iterator<C> beg,istreambuf_iterator<C> end,ios_base & io,ios_base::iostate & err,tm * t,char which)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>
__money_get(current_abi,const facet * f,istreambuf_iterator<C> s,istreambuf_iterator<C> end,bool intl,ios_base & str,ios_base::iostate & err,long double * units,__any_string * digits)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>
__money_put(current_abi,const facet * f,ostreambuf_iterator<C> s,bool intl,ios_base & io,C fill,long double units,const __any_string * digits)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
_M_sso_shim(const locale::id * which) const794   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