default.cc: Do not call members which require a fully established result state.
[gcc.git] / libstdc++-v3 / src / debug.cc
1 // Debugging mode support code -*- C++ -*-
2
3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
25
26 #include <debug/debug.h>
27 #include <debug/safe_sequence.h>
28 #include <debug/safe_iterator.h>
29 #include <algorithm>
30 #include <cassert>
31 #include <cstring>
32 #include <cctype>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <functional>
36
37 using namespace std;
38
39 namespace
40 {
41 /** Returns different instances of __mutex depending on the passed address
42 * in order to limit contention without breaking current library binary
43 * compatibility. */
44 __gnu_cxx::__mutex&
45 get_safe_base_mutex(void* __address)
46 {
47 const size_t mask = 0xf;
48 static __gnu_cxx::__mutex safe_base_mutex[mask + 1];
49 const size_t index = _Hash_impl::hash(__address) & mask;
50 return safe_base_mutex[index];
51 }
52
53 void
54 swap_seq(__gnu_debug::_Safe_sequence_base& __lhs,
55 __gnu_debug::_Safe_sequence_base& __rhs)
56 {
57 swap(__lhs._M_iterators, __rhs._M_iterators);
58 swap(__lhs._M_const_iterators, __rhs._M_const_iterators);
59 swap(__lhs._M_version, __rhs._M_version);
60 __gnu_debug::_Safe_iterator_base* __iter;
61 for (__iter = __rhs._M_iterators; __iter; __iter = __iter->_M_next)
62 __iter->_M_sequence = &__rhs;
63 for (__iter = __lhs._M_iterators; __iter; __iter = __iter->_M_next)
64 __iter->_M_sequence = &__lhs;
65 for (__iter = __rhs._M_const_iterators; __iter; __iter = __iter->_M_next)
66 __iter->_M_sequence = &__rhs;
67 for (__iter = __lhs._M_const_iterators; __iter; __iter = __iter->_M_next)
68 __iter->_M_sequence = &__lhs;
69 }
70 } // anonymous namespace
71
72 namespace __gnu_debug
73 {
74 const char* _S_debug_messages[] =
75 {
76 "function requires a valid iterator range [%1.name;, %2.name;)",
77 "attempt to insert into container with a singular iterator",
78 "attempt to insert into container with an iterator"
79 " from a different container",
80 "attempt to erase from container with a %2.state; iterator",
81 "attempt to erase from container with an iterator"
82 " from a different container",
83 "attempt to subscript container with out-of-bounds index %2;,"
84 " but container only holds %3; elements",
85 "attempt to access an element in an empty container",
86 "elements in iterator range [%1.name;, %2.name;)"
87 " are not partitioned by the value %3;",
88 "elements in iterator range [%1.name;, %2.name;)"
89 " are not partitioned by the predicate %3; and value %4;",
90 "elements in iterator range [%1.name;, %2.name;) are not sorted",
91 "elements in iterator range [%1.name;, %2.name;)"
92 " are not sorted according to the predicate %3;",
93 "elements in iterator range [%1.name;, %2.name;) do not form a heap",
94 "elements in iterator range [%1.name;, %2.name;)"
95 " do not form a heap with respect to the predicate %3;",
96 "attempt to write through a singular bitset reference",
97 "attempt to read from a singular bitset reference",
98 "attempt to flip a singular bitset reference",
99 "attempt to splice a list into itself",
100 "attempt to splice lists with inequal allocators",
101 "attempt to splice elements referenced by a %1.state; iterator",
102 "attempt to splice an iterator from a different container",
103 "splice destination %1.name;"
104 " occurs within source range [%2.name;, %3.name;)",
105 "attempt to initialize an iterator that will immediately become singular",
106 "attempt to copy-construct an iterator from a singular iterator",
107 "attempt to construct a constant iterator"
108 " from a singular mutable iterator",
109 "attempt to copy from a singular iterator",
110 "attempt to dereference a %1.state; iterator",
111 "attempt to increment a %1.state; iterator",
112 "attempt to decrement a %1.state; iterator",
113 "attempt to subscript a %1.state; iterator %2; step from"
114 " its current position, which falls outside its dereferenceable range",
115 "attempt to advance a %1.state; iterator %2; steps,"
116 " which falls outside its valid range",
117 "attempt to retreat a %1.state; iterator %2; steps,"
118 " which falls outside its valid range",
119 "attempt to compare a %1.state; iterator to a %2.state; iterator",
120 "attempt to compare iterators from different sequences",
121 "attempt to order a %1.state; iterator to a %2.state; iterator",
122 "attempt to order iterators from different sequences",
123 "attempt to compute the difference between a %1.state;"
124 " iterator to a %2.state; iterator",
125 "attempt to compute the different between two iterators"
126 " from different sequences",
127 "attempt to dereference an end-of-stream istream_iterator",
128 "attempt to increment an end-of-stream istream_iterator",
129 "attempt to output via an ostream_iterator with no associated stream",
130 "attempt to dereference an end-of-stream istreambuf_iterator"
131 " (this is a GNU extension)",
132 "attempt to increment an end-of-stream istreambuf_iterator",
133 "attempt to insert into container after an end iterator",
134 "attempt to erase from container after a %2.state; iterator not followed"
135 " by a dereferenceable one",
136 "function requires a valid iterator range (%2.name;, %3.name;)"
137 ", \"%2.name;\" shall be before and not equal to \"%3.name;\""
138 };
139
140 void
141 _Safe_sequence_base::
142 _M_detach_all()
143 {
144 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
145 for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
146 {
147 _Safe_iterator_base* __old = __iter;
148 __iter = __iter->_M_next;
149 __old->_M_reset();
150 }
151 _M_iterators = 0;
152
153 for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
154 {
155 _Safe_iterator_base* __old = __iter2;
156 __iter2 = __iter2->_M_next;
157 __old->_M_reset();
158 }
159 _M_const_iterators = 0;
160 }
161
162 void
163 _Safe_sequence_base::
164 _M_detach_singular()
165 {
166 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
167 for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
168 {
169 _Safe_iterator_base* __old = __iter;
170 __iter = __iter->_M_next;
171 if (__old->_M_singular())
172 __old->_M_detach_single();
173 }
174
175 for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
176 {
177 _Safe_iterator_base* __old = __iter2;
178 __iter2 = __iter2->_M_next;
179 if (__old->_M_singular())
180 __old->_M_detach_single();
181 }
182 }
183
184 void
185 _Safe_sequence_base::
186 _M_revalidate_singular()
187 {
188 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
189 for (_Safe_iterator_base* __iter = _M_iterators; __iter;
190 __iter = __iter->_M_next)
191 __iter->_M_version = _M_version;
192
193 for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;
194 __iter2 = __iter2->_M_next)
195 __iter2->_M_version = _M_version;
196 }
197
198 void
199 _Safe_sequence_base::
200 _M_swap(_Safe_sequence_base& __x)
201 {
202 // We need to lock both sequences to swap
203 using namespace __gnu_cxx;
204 __mutex *__this_mutex = &_M_get_mutex();
205 __mutex *__x_mutex = &__x._M_get_mutex();
206 if (__this_mutex == __x_mutex)
207 {
208 __scoped_lock __lock(*__this_mutex);
209 swap_seq(*this, __x);
210 }
211 else
212 {
213 __scoped_lock __l1(__this_mutex < __x_mutex
214 ? *__this_mutex : *__x_mutex);
215 __scoped_lock __l2(__this_mutex < __x_mutex
216 ? *__x_mutex : *__this_mutex);
217 swap_seq(*this, __x);
218 }
219 }
220
221 __gnu_cxx::__mutex&
222 _Safe_sequence_base::
223 _M_get_mutex() throw ()
224 { return get_safe_base_mutex(this); }
225
226 void
227 _Safe_sequence_base::
228 _M_attach(_Safe_iterator_base* __it, bool __constant)
229 {
230 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
231 _M_attach_single(__it, __constant);
232 }
233
234 void
235 _Safe_sequence_base::
236 _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ()
237 {
238 _Safe_iterator_base*& __its =
239 __constant ? _M_const_iterators : _M_iterators;
240 __it->_M_next = __its;
241 if (__it->_M_next)
242 __it->_M_next->_M_prior = __it;
243 __its = __it;
244 }
245
246 void
247 _Safe_sequence_base::
248 _M_detach(_Safe_iterator_base* __it)
249 {
250 // Remove __it from this sequence's list
251 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
252 _M_detach_single(__it);
253 }
254
255 void
256 _Safe_sequence_base::
257 _M_detach_single(_Safe_iterator_base* __it) throw ()
258 {
259 // Remove __it from this sequence's list
260 __it->_M_unlink();
261 if (_M_const_iterators == __it)
262 _M_const_iterators = __it->_M_next;
263 if (_M_iterators == __it)
264 _M_iterators = __it->_M_next;
265 }
266
267 void
268 _Safe_iterator_base::
269 _M_attach(_Safe_sequence_base* __seq, bool __constant)
270 {
271 _M_detach();
272
273 // Attach to the new sequence (if there is one)
274 if (__seq)
275 {
276 _M_sequence = __seq;
277 _M_version = _M_sequence->_M_version;
278 _M_sequence->_M_attach(this, __constant);
279 }
280 }
281
282 void
283 _Safe_iterator_base::
284 _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ()
285 {
286 _M_detach_single();
287
288 // Attach to the new sequence (if there is one)
289 if (__seq)
290 {
291 _M_sequence = __seq;
292 _M_version = _M_sequence->_M_version;
293 _M_sequence->_M_attach_single(this, __constant);
294 }
295 }
296
297 void
298 _Safe_iterator_base::
299 _M_detach()
300 {
301 if (_M_sequence)
302 {
303 _M_sequence->_M_detach(this);
304 }
305
306 _M_reset();
307 }
308
309 void
310 _Safe_iterator_base::
311 _M_detach_single() throw ()
312 {
313 if (_M_sequence)
314 {
315 _M_sequence->_M_detach_single(this);
316 }
317
318 _M_reset();
319 }
320
321 void
322 _Safe_iterator_base::
323 _M_reset() throw ()
324 {
325 _M_sequence = 0;
326 _M_version = 0;
327 _M_prior = 0;
328 _M_next = 0;
329 }
330
331 bool
332 _Safe_iterator_base::
333 _M_singular() const throw ()
334 { return !_M_sequence || _M_version != _M_sequence->_M_version; }
335
336 bool
337 _Safe_iterator_base::
338 _M_can_compare(const _Safe_iterator_base& __x) const throw ()
339 {
340 return (!_M_singular()
341 && !__x._M_singular() && _M_sequence == __x._M_sequence);
342 }
343
344 __gnu_cxx::__mutex&
345 _Safe_iterator_base::
346 _M_get_mutex() throw ()
347 { return get_safe_base_mutex(_M_sequence); }
348
349 void
350 _Error_formatter::_Parameter::
351 _M_print_field(const _Error_formatter* __formatter, const char* __name) const
352 {
353 assert(this->_M_kind != _Parameter::__unused_param);
354 const int __bufsize = 64;
355 char __buf[__bufsize];
356
357 if (_M_kind == __iterator)
358 {
359 if (strcmp(__name, "name") == 0)
360 {
361 assert(_M_variant._M_iterator._M_name);
362 __formatter->_M_print_word(_M_variant._M_iterator._M_name);
363 }
364 else if (strcmp(__name, "address") == 0)
365 {
366 __formatter->_M_format_word(__buf, __bufsize, "%p",
367 _M_variant._M_iterator._M_address);
368 __formatter->_M_print_word(__buf);
369 }
370 else if (strcmp(__name, "type") == 0)
371 {
372 if (!_M_variant._M_iterator._M_type)
373 __formatter->_M_print_word("<unknown type>");
374 else
375 // TBD: demangle!
376 __formatter->_M_print_word(_M_variant._M_iterator.
377 _M_type->name());
378 }
379 else if (strcmp(__name, "constness") == 0)
380 {
381 static const char* __constness_names[__last_constness] =
382 {
383 "<unknown>",
384 "constant",
385 "mutable"
386 };
387 __formatter->_M_print_word(__constness_names[_M_variant.
388 _M_iterator.
389 _M_constness]);
390 }
391 else if (strcmp(__name, "state") == 0)
392 {
393 static const char* __state_names[__last_state] =
394 {
395 "<unknown>",
396 "singular",
397 "dereferenceable (start-of-sequence)",
398 "dereferenceable",
399 "past-the-end",
400 "before-begin"
401 };
402 __formatter->_M_print_word(__state_names[_M_variant.
403 _M_iterator._M_state]);
404 }
405 else if (strcmp(__name, "sequence") == 0)
406 {
407 assert(_M_variant._M_iterator._M_sequence);
408 __formatter->_M_format_word(__buf, __bufsize, "%p",
409 _M_variant._M_iterator._M_sequence);
410 __formatter->_M_print_word(__buf);
411 }
412 else if (strcmp(__name, "seq_type") == 0)
413 {
414 if (!_M_variant._M_iterator._M_seq_type)
415 __formatter->_M_print_word("<unknown seq_type>");
416 else
417 // TBD: demangle!
418 __formatter->_M_print_word(_M_variant._M_iterator.
419 _M_seq_type->name());
420 }
421 else
422 assert(false);
423 }
424 else if (_M_kind == __sequence)
425 {
426 if (strcmp(__name, "name") == 0)
427 {
428 assert(_M_variant._M_sequence._M_name);
429 __formatter->_M_print_word(_M_variant._M_sequence._M_name);
430 }
431 else if (strcmp(__name, "address") == 0)
432 {
433 assert(_M_variant._M_sequence._M_address);
434 __formatter->_M_format_word(__buf, __bufsize, "%p",
435 _M_variant._M_sequence._M_address);
436 __formatter->_M_print_word(__buf);
437 }
438 else if (strcmp(__name, "type") == 0)
439 {
440 if (!_M_variant._M_sequence._M_type)
441 __formatter->_M_print_word("<unknown type>");
442 else
443 // TBD: demangle!
444 __formatter->_M_print_word(_M_variant._M_sequence.
445 _M_type->name());
446 }
447 else
448 assert(false);
449 }
450 else if (_M_kind == __integer)
451 {
452 if (strcmp(__name, "name") == 0)
453 {
454 assert(_M_variant._M_integer._M_name);
455 __formatter->_M_print_word(_M_variant._M_integer._M_name);
456 }
457 else
458 assert(false);
459 }
460 else if (_M_kind == __string)
461 {
462 if (strcmp(__name, "name") == 0)
463 {
464 assert(_M_variant._M_string._M_name);
465 __formatter->_M_print_word(_M_variant._M_string._M_name);
466 }
467 else
468 assert(false);
469 }
470 else
471 {
472 assert(false);
473 }
474 }
475
476 void
477 _Error_formatter::_Parameter::
478 _M_print_description(const _Error_formatter* __formatter) const
479 {
480 const int __bufsize = 128;
481 char __buf[__bufsize];
482
483 if (_M_kind == __iterator)
484 {
485 __formatter->_M_print_word("iterator ");
486 if (_M_variant._M_iterator._M_name)
487 {
488 __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
489 _M_variant._M_iterator._M_name);
490 __formatter->_M_print_word(__buf);
491 }
492
493 __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
494 _M_variant._M_iterator._M_address);
495 __formatter->_M_print_word(__buf);
496 if (_M_variant._M_iterator._M_type)
497 {
498 __formatter->_M_print_word("type = ");
499 _M_print_field(__formatter, "type");
500
501 if (_M_variant._M_iterator._M_constness != __unknown_constness)
502 {
503 __formatter->_M_print_word(" (");
504 _M_print_field(__formatter, "constness");
505 __formatter->_M_print_word(" iterator)");
506 }
507 __formatter->_M_print_word(";\n");
508 }
509
510 if (_M_variant._M_iterator._M_state != __unknown_state)
511 {
512 __formatter->_M_print_word(" state = ");
513 _M_print_field(__formatter, "state");
514 __formatter->_M_print_word(";\n");
515 }
516
517 if (_M_variant._M_iterator._M_sequence)
518 {
519 __formatter->_M_print_word(" references sequence ");
520 if (_M_variant._M_iterator._M_seq_type)
521 {
522 __formatter->_M_print_word("with type `");
523 _M_print_field(__formatter, "seq_type");
524 __formatter->_M_print_word("' ");
525 }
526
527 __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n",
528 _M_variant._M_sequence._M_address);
529 __formatter->_M_print_word(__buf);
530 }
531 __formatter->_M_print_word("}\n");
532 }
533 else if (_M_kind == __sequence)
534 {
535 __formatter->_M_print_word("sequence ");
536 if (_M_variant._M_sequence._M_name)
537 {
538 __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
539 _M_variant._M_sequence._M_name);
540 __formatter->_M_print_word(__buf);
541 }
542
543 __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
544 _M_variant._M_sequence._M_address);
545 __formatter->_M_print_word(__buf);
546
547 if (_M_variant._M_sequence._M_type)
548 {
549 __formatter->_M_print_word(" type = ");
550 _M_print_field(__formatter, "type");
551 __formatter->_M_print_word(";\n");
552 }
553 __formatter->_M_print_word("}\n");
554 }
555 }
556
557 const _Error_formatter&
558 _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
559 { return this->_M_message(_S_debug_messages[__id]); }
560
561 void
562 _Error_formatter::_M_error() const
563 {
564 const int __bufsize = 128;
565 char __buf[__bufsize];
566
567 // Emit file & line number information
568 _M_column = 1;
569 _M_wordwrap = false;
570 if (_M_file)
571 {
572 _M_format_word(__buf, __bufsize, "%s:", _M_file);
573 _M_print_word(__buf);
574 _M_column += strlen(__buf);
575 }
576
577 if (_M_line > 0)
578 {
579 _M_format_word(__buf, __bufsize, "%u:", _M_line);
580 _M_print_word(__buf);
581 _M_column += strlen(__buf);
582 }
583
584 if (_M_max_length)
585 _M_wordwrap = true;
586 _M_print_word("error: ");
587
588 // Print the error message
589 assert(_M_text);
590 _M_print_string(_M_text);
591 _M_print_word(".\n");
592
593 // Emit descriptions of the objects involved in the operation
594 _M_wordwrap = false;
595 bool __has_noninteger_parameters = false;
596 for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
597 {
598 if (_M_parameters[__i]._M_kind == _Parameter::__iterator
599 || _M_parameters[__i]._M_kind == _Parameter::__sequence)
600 {
601 if (!__has_noninteger_parameters)
602 {
603 _M_first_line = true;
604 _M_print_word("\nObjects involved in the operation:\n");
605 __has_noninteger_parameters = true;
606 }
607 _M_parameters[__i]._M_print_description(this);
608 }
609 }
610
611 abort();
612 }
613
614 template<typename _Tp>
615 void
616 _Error_formatter::_M_format_word(char* __buf,
617 int __n __attribute__ ((__unused__)),
618 const char* __fmt, _Tp __s) const throw ()
619 {
620 #ifdef _GLIBCXX_USE_C99
621 std::snprintf(__buf, __n, __fmt, __s);
622 #else
623 std::sprintf(__buf, __fmt, __s);
624 #endif
625 }
626
627
628 void
629 _Error_formatter::_M_print_word(const char* __word) const
630 {
631 if (!_M_wordwrap)
632 {
633 fprintf(stderr, "%s", __word);
634 return;
635 }
636
637 size_t __length = strlen(__word);
638 if (__length == 0)
639 return;
640
641 if ((_M_column + __length < _M_max_length)
642 || (__length >= _M_max_length && _M_column == 1))
643 {
644 // If this isn't the first line, indent
645 if (_M_column == 1 && !_M_first_line)
646 {
647 char __spacing[_M_indent + 1];
648 for (int i = 0; i < _M_indent; ++i)
649 __spacing[i] = ' ';
650 __spacing[_M_indent] = '\0';
651 fprintf(stderr, "%s", __spacing);
652 _M_column += _M_indent;
653 }
654
655 fprintf(stderr, "%s", __word);
656 _M_column += __length;
657
658 if (__word[__length - 1] == '\n')
659 {
660 _M_first_line = false;
661 _M_column = 1;
662 }
663 }
664 else
665 {
666 _M_column = 1;
667 _M_print_word("\n");
668 _M_print_word(__word);
669 }
670 }
671
672 void
673 _Error_formatter::
674 _M_print_string(const char* __string) const
675 {
676 const char* __start = __string;
677 const char* __finish = __start;
678 const int __bufsize = 128;
679 char __buf[__bufsize];
680
681 while (*__start)
682 {
683 if (*__start != '%')
684 {
685 // [__start, __finish) denotes the next word
686 __finish = __start;
687 while (isalnum(*__finish))
688 ++__finish;
689 if (__start == __finish)
690 ++__finish;
691 if (isspace(*__finish))
692 ++__finish;
693
694 const ptrdiff_t __len = __finish - __start;
695 assert(__len < __bufsize);
696 memcpy(__buf, __start, __len);
697 __buf[__len] = '\0';
698 _M_print_word(__buf);
699 __start = __finish;
700
701 // Skip extra whitespace
702 while (*__start == ' ')
703 ++__start;
704
705 continue;
706 }
707
708 ++__start;
709 assert(*__start);
710 if (*__start == '%')
711 {
712 _M_print_word("%");
713 ++__start;
714 continue;
715 }
716
717 // Get the parameter number
718 assert(*__start >= '1' && *__start <= '9');
719 size_t __param = *__start - '0';
720 --__param;
721 assert(__param < _M_num_parameters);
722
723 // '.' separates the parameter number from the field
724 // name, if there is one.
725 ++__start;
726 if (*__start != '.')
727 {
728 assert(*__start == ';');
729 ++__start;
730 __buf[0] = '\0';
731 if (_M_parameters[__param]._M_kind == _Parameter::__integer)
732 {
733 _M_format_word(__buf, __bufsize, "%ld",
734 _M_parameters[__param]._M_variant._M_integer._M_value);
735 _M_print_word(__buf);
736 }
737 else if (_M_parameters[__param]._M_kind == _Parameter::__string)
738 _M_print_string(_M_parameters[__param]._M_variant._M_string._M_value);
739 continue;
740 }
741
742 // Extract the field name we want
743 enum { __max_field_len = 16 };
744 char __field[__max_field_len];
745 int __field_idx = 0;
746 ++__start;
747 while (*__start != ';')
748 {
749 assert(*__start);
750 assert(__field_idx < __max_field_len-1);
751 __field[__field_idx++] = *__start++;
752 }
753 ++__start;
754 __field[__field_idx] = 0;
755
756 _M_parameters[__param]._M_print_field(this, __field);
757 }
758 }
759
760 void
761 _Error_formatter::_M_get_max_length() const throw ()
762 {
763 const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
764 if (__nptr)
765 {
766 char* __endptr;
767 const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
768 if (*__nptr != '\0' && *__endptr == '\0')
769 _M_max_length = __ret;
770 }
771 }
772
773 // Instantiations.
774 template
775 void
776 _Error_formatter::_M_format_word(char*, int, const char*,
777 const void*) const;
778
779 template
780 void
781 _Error_formatter::_M_format_word(char*, int, const char*, long) const;
782
783 template
784 void
785 _Error_formatter::_M_format_word(char*, int, const char*,
786 std::size_t) const;
787
788 template
789 void
790 _Error_formatter::_M_format_word(char*, int, const char*,
791 const char*) const;
792 } // namespace __gnu_debug