diff mbox

debug mode maintenance patch

Message ID 55632418.6000007@gmail.com
State New
Headers show

Commit Message

François Dumont May 25, 2015, 1:31 p.m. UTC
Hi

     This is a patch to clean the debug mode code.

     I have introduced a new debug header, assertions.h, so that headers 
that only need _GLIBCXX_DEBUG_ASSERT do not have to include the big 
debug.h. I also introduce functions.tcc to isolate implementation of 
__foreign_iterator which require a number of other headers.

     I reorganized _Error_formatter. Nested _Parameter is now public 
like several format methods so that I am able to move some code to 
debug.cc. I would have needed to export new symbols otherwise. I 
introduced 2 new type of debug parameters, __instance for any functor, 
__iterator_value_type to report iterator value_type. I will use those in 
new debug checks to come.

     Note that I try to regenerate include/Makefile.in with autoreconf 
2.64 but it was producing a lot of modifications in all Makefile.in. Can 
someone check if those files are up to date ?

2015-02-19  François Dumont  <fdumont@gcc.gnu.org>

     * include/debug/debug.h ([_GLIBCXX_DEBUG_ASSERT,
     _GLIBCXX_DEBUG_PEDASSERT, _GLIBCXX_DEBUG_ONLY]): Move definition...
     * include/debug/assertions.h: ...here, new.
     * include/debug/formatter.h
     (struct _Error_formatter::_Is_iterator_value_type): New.
     (struct _Error_formatter::_Is_instance): New.
     (struct _Error_formatter::_Parameter): Make public and not friend
     anymore.
     (_Error_formatter::_Parameter::__instance): New _M_kind enum entry.
     (_Error_formatter::_Parameter::__iterator_value_type): New _M_kind enum
     entry.
     (struct _Error_formatter::_Parameter::_Type): New.
     (struct _Error_formatter::_Parameter::_Instance): New, inherit from
     latter.
     (union _Error_formatter::_Parameter::_M_variant): Reorganize.
     (_Parameter(_Iterator const&, const char*, _Is_iterator)): Make all
     overloads take iterator through a const reference.
     (_Parameter(const _Iterator&, const char*, _Is_iterator_value_type)):
     New.
     (_Parameter(const _Type&, const char*, _Is_instance)): New.
     (_Error_formatter::_M_print_type): Delete.
     (_Error_formatter::_M_iterator_value_type): New.
     (_Error_formatter::_M_instance): New.
     * include/debug/functions.h (__foreign_iterator): Move definition...
     * include/debug/functions.tcc: ...here, new.
     * include/Makefile.am: Add new above debug files.
     * include/Makefile.in: Regenerate.
     * include/debug/safe_iterator.h: Replace debug.h include with
     assertions.h.
     (__check_dereferenceable, __valid_range): Move here overload for
     _Safe_iterator.
     (struct __is_safe_random_iterator): Move here partial specialization
     for _Safe_iterator.
     (__check_singular_aux): Move...
     * include/debug/safe_base.h (__check_singular_aux): ... here.
     * include/debug/safe_local_iterator.h (__check_dereferenceable)
     (__valid_range): Move here overload for _Safe_local_iterator.
     * include/debug/safe_sequence.h: Replace debug.h with assertions.h.
     Remove _Safe_iterator declaration.
     * include/debug/safe_unordered_container.h: Replace debug.h with
     assertions.h.
     * include/debug/array: Replace safe_sequence.h include with
     formatter.h and macros.h.
     * include/debug/deque: Include functions.tcc.
     * include/debug/forward_list: Likewise.
     * include/debug/list: Likewise.
     * include/debug/string: Likewise.
     * include/debug/vector: Likewise.
     * include/bits/unique_ptr.h: Replace debug.h include with new
     assertions.h.
     * include/bits/stl_iterator_base_funcs.h: Likewise.
     * testsuite/23_containers/array/tuple_interface/get_debug_neg.cc:
     Adjust dg-error line number.
     * testsuite/23_containers/array/tuple_interface/
     tuple_element_debug_neg.cc: Likewise.
     * src/c++11/debug.cc: Adapt.

Tested under Linux x86_64 debug mode.

Will commit in a couple of days if no complain.

François

Comments

Jonathan Wakely May 25, 2015, 6:41 p.m. UTC | #1
On 25/05/15 15:31 +0200, François Dumont wrote:
>Hi
>
>    This is a patch to clean the debug mode code.
>
>    I have introduced a new debug header, assertions.h, so that 
>headers that only need _GLIBCXX_DEBUG_ASSERT do not have to include 
>the big debug.h. I also introduce functions.tcc to isolate 
>implementation of __foreign_iterator which require a number of other 
>headers.

All other uses of .tcc extensions are headers included automatically
at the bottom of the corresponding .h header, so other headers never
need to do #include <foo.tcc> because that appears at the end of
<foo.h> (or <foo> for standard headers).

Also, .tcc is meant to be for definitions of non-inline templates that
are declared (but not defined) in the header that includes the .tcc
file, but all the functions you're moving to <debug/functions.tcc> are
still small and inline.

If the point is just to move some functions to a different header
because not all consumers of functions.h need those functions then I
think it should have a different name, not pretend to be related to
functions.h

I'm not convinced moving them to a separate header is even a good
idea. Surely most headers that include <debug/functions.h> already end
up including <bits/move.h> and <type_traits> anyway?


>    * include/debug/debug.h ([_GLIBCXX_DEBUG_ASSERT,
>    _GLIBCXX_DEBUG_PEDASSERT, _GLIBCXX_DEBUG_ONLY]): Move definition...

These names should not be in square brackets (square brackets are used
to indicate conditional changes, see
http://www.gnu.org/prep/standards/html_node/Conditional-Changes.html)

>    (__check_dereferenceable, __valid_range): Move here overload for
>    _Safe_iterator.
>    (struct __is_safe_random_iterator): Move here partial specialization
>    for _Safe_iterator.

These should say "Move X here" not "Move here X".

>Index: include/debug/functions.tcc
>===================================================================
>--- include/debug/functions.tcc	(revision 0)
>+++ include/debug/functions.tcc	(working copy)
>@@ -0,0 +1,159 @@
>+// Debugging support implementation -*- C++ -*-
>+
>+// Copyright (C) 2015 Free Software Foundation, Inc.

It worries me when we move existing code to new headers and only give
it the current year as the copyright date. The copyright applies to
the code, which is older than 2015, not to the file itself.

I think I've asked about this before and been told that only adding
the current year is correct, but that seems wrong to me. I'll try to
confirm that.
Pedro Alves May 26, 2015, 8:45 a.m. UTC | #2
On 05/25/2015 07:41 PM, Jonathan Wakely wrote:

>> Index: include/debug/functions.tcc
>> ===================================================================
>> --- include/debug/functions.tcc	(revision 0)
>> +++ include/debug/functions.tcc	(working copy)
>> @@ -0,0 +1,159 @@
>> +// Debugging support implementation -*- C++ -*-
>> +
>> +// Copyright (C) 2015 Free Software Foundation, Inc.
> 
> It worries me when we move existing code to new headers and only give
> it the current year as the copyright date. The copyright applies to
> the code, which is older than 2015, not to the file itself.
> 
> I think I've asked about this before and been told that only adding
> the current year is correct, but that seems wrong to me. I'll try to
> confirm that.

You should retain the old copyright years in the new file.

Here's FSF's response when inquired about that a while ago:

 https://sourceware.org/ml/gdb-patches/2012-04/msg00640.html

Thanks,
Pedro Alves
Jonathan Wakely May 26, 2015, 9:19 a.m. UTC | #3
On 26/05/15 09:45 +0100, Pedro Alves wrote:
>On 05/25/2015 07:41 PM, Jonathan Wakely wrote:
>
>>> Index: include/debug/functions.tcc
>>> ===================================================================
>>> --- include/debug/functions.tcc	(revision 0)
>>> +++ include/debug/functions.tcc	(working copy)
>>> @@ -0,0 +1,159 @@
>>> +// Debugging support implementation -*- C++ -*-
>>> +
>>> +// Copyright (C) 2015 Free Software Foundation, Inc.
>>
>> It worries me when we move existing code to new headers and only give
>> it the current year as the copyright date. The copyright applies to
>> the code, which is older than 2015, not to the file itself.
>>
>> I think I've asked about this before and been told that only adding
>> the current year is correct, but that seems wrong to me. I'll try to
>> confirm that.
>
>You should retain the old copyright years in the new file.
>
>Here's FSF's response when inquired about that a while ago:
>
> https://sourceware.org/ml/gdb-patches/2012-04/msg00640.html

Thanks, Pedro.

Glad to hear I've been doing it right!

François, therefore please ensure you keep the right copyright years
when moving code to new files (I'm still not convinced a new file is
useful here though).
Jonathan Wakely May 29, 2015, 10:40 a.m. UTC | #4
On 28/05/15 22:32 +0200, François Dumont wrote:
>Sorry, I saw it used so many times for macros that I though it was the 
>right way to report macro modifications.

The changelog style is fairly complicated :-)

>I also replicate Copyrights from debug.h to assertions.h.
>
>    * include/debug/debug.h (_GLIBCXX_DEBUG_ASSERT,
>    _GLIBCXX_DEBUG_PEDASSERT, _GLIBCXX_DEBUG_ONLY): Move definition...
>    * include/debug/assertions.h: ...here, new.
>    * include/debug/formatter.h
>    (struct _Error_formatter::_Is_iterator_value_type): New.
>    (struct _Error_formatter::_Is_instance): New.
>    (struct _Error_formatter::_Parameter): Make public and not friend
>    anymore.
>    (_Error_formatter::_Parameter::__instance): New _M_kind enum entry.
>    (_Error_formatter::_Parameter::__iterator_value_type): New _M_kind enum
>    entry.
>    (struct _Error_formatter::_Parameter::_Type): New.
>    (struct _Error_formatter::_Parameter::_Instance): New, inherit from
>    latter.
>    (union _Error_formatter::_Parameter::_M_variant): Reorganize.

I don't think we need to say 'struct' or 'union' either, because we're
not writing C, and they aren't needed in C++, but no big deal.

>Ok to commit ?

Yes, looks good, thanks.
diff mbox

Patch

Index: include/Makefile.am
===================================================================
--- include/Makefile.am	(revision 223630)
+++ include/Makefile.am	(working copy)
@@ -759,6 +759,7 @@ 
 debug_builddir = ./debug
 debug_headers = \
 	${debug_srcdir}/array \
+	${debug_srcdir}/assertions.h \
 	${debug_srcdir}/bitset \
 	${debug_srcdir}/debug.h \
 	${debug_srcdir}/deque \
@@ -765,6 +766,7 @@ 
 	${debug_srcdir}/formatter.h \
 	${debug_srcdir}/forward_list \
 	${debug_srcdir}/functions.h \
+	${debug_srcdir}/functions.tcc \
 	${debug_srcdir}/list \
 	${debug_srcdir}/map \
 	${debug_srcdir}/macros.h \
Index: include/Makefile.in
===================================================================
--- include/Makefile.in	(revision 223630)
+++ include/Makefile.in	(working copy)
@@ -1040,6 +1040,7 @@ 
 debug_builddir = ./debug
 debug_headers = \
 	${debug_srcdir}/array \
+	${debug_srcdir}/assertions.h \
 	${debug_srcdir}/bitset \
 	${debug_srcdir}/debug.h \
 	${debug_srcdir}/deque \
@@ -1046,6 +1047,7 @@ 
 	${debug_srcdir}/formatter.h \
 	${debug_srcdir}/forward_list \
 	${debug_srcdir}/functions.h \
+	${debug_srcdir}/functions.tcc \
 	${debug_srcdir}/list \
 	${debug_srcdir}/map \
 	${debug_srcdir}/macros.h \
Index: include/bits/stl_iterator_base_funcs.h
===================================================================
--- include/bits/stl_iterator_base_funcs.h	(revision 223630)
+++ include/bits/stl_iterator_base_funcs.h	(working copy)
@@ -62,7 +62,7 @@ 
 #pragma GCC system_header
 
 #include <bits/concept_check.h>
-#include <debug/debug.h>
+#include <debug/assertions.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
Index: include/bits/unique_ptr.h
===================================================================
--- include/bits/unique_ptr.h	(revision 223630)
+++ include/bits/unique_ptr.h	(working copy)
@@ -31,7 +31,7 @@ 
 #define _UNIQUE_PTR_H 1
 
 #include <bits/c++config.h>
-#include <debug/debug.h>
+#include <debug/assertions.h>
 #include <type_traits>
 #include <utility>
 #include <tuple>
Index: include/debug/array
===================================================================
--- include/debug/array	(revision 223630)
+++ include/debug/array	(working copy)
@@ -31,7 +31,8 @@ 
 
 #pragma GCC system_header
 
-#include <debug/safe_sequence.h>
+#include <debug/formatter.h>
+#include <debug/macros.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
Index: include/debug/assertions.h
===================================================================
--- include/debug/assertions.h	(revision 0)
+++ include/debug/assertions.h	(working copy)
@@ -0,0 +1,52 @@ 
+// Debugging support implementation -*- C++ -*-
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file debug/assertions.h
+ *  This file is a GNU debug extension to the Standard C++ Library.
+ */
+
+#ifndef _GLIBCXX_DEBUG_ASSERTIONS_H
+#define _GLIBCXX_DEBUG_ASSERTIONS_H 1
+
+#ifndef _GLIBCXX_DEBUG
+
+# define _GLIBCXX_DEBUG_ASSERT(_Condition)
+# define _GLIBCXX_DEBUG_PEDASSERT(_Condition)
+# define _GLIBCXX_DEBUG_ONLY(_Statement) ;
+
+#else
+
+#define _GLIBCXX_DEBUG_ASSERT(_Condition) __glibcxx_assert(_Condition)
+
+#ifdef _GLIBCXX_DEBUG_PEDANTIC
+# define _GLIBCXX_DEBUG_PEDASSERT(_Condition) _GLIBCXX_DEBUG_ASSERT(_Condition)
+#else
+# define _GLIBCXX_DEBUG_PEDASSERT(_Condition)
+#endif
+
+# define _GLIBCXX_DEBUG_ONLY(_Statement) _Statement
+
+#endif
+
+#endif // _GLIBCXX_DEBUG_ASSERTIONS
Index: include/debug/debug.h
===================================================================
--- include/debug/debug.h	(revision 223630)
+++ include/debug/debug.h	(working copy)
@@ -37,6 +37,8 @@ 
  *  the standard library algorithms.
 */
 
+#include <debug/assertions.h>
+
 // Debug mode namespaces.
 
 /**
@@ -58,9 +60,6 @@ 
 
 #ifndef _GLIBCXX_DEBUG
 
-# define _GLIBCXX_DEBUG_ASSERT(_Condition)
-# define _GLIBCXX_DEBUG_PEDASSERT(_Condition)
-# define _GLIBCXX_DEBUG_ONLY(_Statement) ;
 # define __glibcxx_requires_cond(_Cond,_Msg)
 # define __glibcxx_requires_valid_range(_First,_Last)
 # define __glibcxx_requires_non_empty_range(_First,_Last)
@@ -83,16 +82,6 @@ 
 
 # include <debug/macros.h>
 
-#define _GLIBCXX_DEBUG_ASSERT(_Condition) __glibcxx_assert(_Condition)
-
-#ifdef _GLIBCXX_DEBUG_PEDANTIC
-# define _GLIBCXX_DEBUG_PEDASSERT(_Condition) _GLIBCXX_DEBUG_ASSERT(_Condition)
-#else
-# define _GLIBCXX_DEBUG_PEDASSERT(_Condition)
-#endif
-
-# define _GLIBCXX_DEBUG_ONLY(_Statement) _Statement
-
 # define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg)
 # define __glibcxx_requires_valid_range(_First,_Last) \
      __glibcxx_check_valid_range(_First,_Last)
Index: include/debug/deque
===================================================================
--- include/debug/deque	(revision 223630)
+++ include/debug/deque	(working copy)
@@ -636,4 +636,6 @@ 
 } // namespace __debug
 } // namespace std
 
+#include <debug/functions.tcc>
+
 #endif
Index: include/debug/formatter.h
===================================================================
--- include/debug/formatter.h	(revision 223630)
+++ include/debug/formatter.h	(working copy)
@@ -154,8 +154,11 @@ 
 
     // Tags denoting the type of parameter for construction
     struct _Is_iterator { };
+    struct _Is_iterator_value_type { };
     struct _Is_sequence { };
+    struct _Is_instance { };
 
+  public:
     // A parameter that may be referenced by an error message
     struct _Parameter
     {
@@ -165,17 +168,27 @@ 
 	__iterator,
 	__sequence,
 	__integer,
-	__string
+	__string,
+	__instance,
+	__iterator_value_type
       } _M_kind;
 
+      struct _Type
+      {
+	const char*		_M_name;
+	const type_info*	_M_type;
+      };
+
+      struct _Instance : _Type
+      {
+	const void*		_M_address;
+      };
+
       union
       {
 	// When _M_kind == __iterator
-	struct
+	struct : _Instance
 	{
-	  const char*		_M_name;
-	  const void*		_M_address;
-	  const type_info*	_M_type;
 	  _Constness		_M_constness;
 	  _Iterator_state	_M_state;
 	  const void*		_M_sequence;
@@ -183,12 +196,7 @@ 
 	} _M_iterator;
 
 	// When _M_kind == __sequence
-	struct
-	{
-	  const char*		_M_name;
-	  const void*		_M_address;
-	  const type_info*	_M_type;
-	} _M_sequence;
+	_Instance _M_sequence;
 
 	// When _M_kind == __integer
 	struct
@@ -203,6 +211,12 @@ 
 	  const char*		_M_name;
 	  const char*		_M_value;
 	} _M_string;
+
+	// When _M_kind == __instance
+	_Instance _M_instance;
+
+	// When _M_kind == __iterator_value_type
+	_Type _M_iterator_value_type;
       } _M_variant;
 
       _Parameter() : _M_kind(__unused_param), _M_variant() { }
@@ -222,7 +236,7 @@ 
       }
 
       template<typename _Iterator, typename _Sequence>
-	_Parameter(const _Safe_iterator<_Iterator, _Sequence>& __it,
+	_Parameter(_Safe_iterator<_Iterator, _Sequence> const& __it,
 		   const char* __name, _Is_iterator)
 	: _M_kind(__iterator),  _M_variant()
 	{
@@ -252,7 +266,7 @@ 
 	}
 
       template<typename _Iterator, typename _Sequence>
-	_Parameter(const _Safe_local_iterator<_Iterator, _Sequence>& __it,
+	_Parameter(_Safe_local_iterator<_Iterator, _Sequence> const& __it,
 		   const char* __name, _Is_iterator)
 	: _M_kind(__iterator),  _M_variant()
 	{
@@ -280,33 +294,33 @@ 
 	}
 
       template<typename _Type>
-	_Parameter(const _Type*& __it, const char* __name, _Is_iterator)
+	_Parameter(const _Type* const& __it, const char* __name, _Is_iterator)
 	: _M_kind(__iterator), _M_variant()
 	{
 	  _M_variant._M_iterator._M_name = __name;
 	  _M_variant._M_iterator._M_address = &__it;
 	  _M_variant._M_iterator._M_type = _GLIBCXX_TYPEID(__it);
-	  _M_variant._M_iterator._M_constness = __mutable_iterator;
-	  _M_variant._M_iterator._M_state = __it? __unknown_state : __singular;
+	  _M_variant._M_iterator._M_constness = __const_iterator;
+	  _M_variant._M_iterator._M_state = __it ? __unknown_state : __singular;
 	  _M_variant._M_iterator._M_sequence = 0;
 	  _M_variant._M_iterator._M_seq_type = 0;
 	}
 
       template<typename _Type>
-	_Parameter(_Type*& __it, const char* __name, _Is_iterator)
+	_Parameter(_Type* const& __it, const char* __name, _Is_iterator)
 	: _M_kind(__iterator), _M_variant()
 	{
 	  _M_variant._M_iterator._M_name = __name;
 	  _M_variant._M_iterator._M_address = &__it;
 	  _M_variant._M_iterator._M_type = _GLIBCXX_TYPEID(__it);
-	  _M_variant._M_iterator._M_constness = __const_iterator;
-	  _M_variant._M_iterator._M_state = __it? __unknown_state : __singular;
+	  _M_variant._M_iterator._M_constness = __mutable_iterator;
+	  _M_variant._M_iterator._M_state = __it ? __unknown_state : __singular;
 	  _M_variant._M_iterator._M_sequence = 0;
 	  _M_variant._M_iterator._M_seq_type = 0;
 	}
 
       template<typename _Iterator>
-	_Parameter(const _Iterator& __it, const char* __name, _Is_iterator)
+	_Parameter(_Iterator const& __it, const char* __name, _Is_iterator)
 	: _M_kind(__iterator), _M_variant()
 	{
 	  _M_variant._M_iterator._M_name = __name;
@@ -314,7 +328,7 @@ 
 	  _M_variant._M_iterator._M_type = _GLIBCXX_TYPEID(__it);
 	  _M_variant._M_iterator._M_constness = __unknown_constness;
 	  _M_variant._M_iterator._M_state =
-	    __gnu_debug::__check_singular(__it)? __singular : __unknown_state;
+	    __gnu_debug::__check_singular(__it) ? __singular : __unknown_state;
 	  _M_variant._M_iterator._M_sequence = 0;
 	  _M_variant._M_iterator._M_seq_type = 0;
 	}
@@ -339,6 +353,25 @@ 
 	  _M_variant._M_sequence._M_type = _GLIBCXX_TYPEID(_Sequence);
 	}
 
+      template<typename _Iterator>
+	_Parameter(const _Iterator& __it, const char* __name,
+		   _Is_iterator_value_type)
+	: _M_kind(__iterator_value_type), _M_variant()
+	{
+	  _M_variant._M_iterator_value_type._M_name = __name;
+	  _M_variant._M_iterator_value_type._M_type =
+	    _GLIBCXX_TYPEID(typename std::iterator_traits<_Iterator>::value_type);
+	}
+
+      template<typename _Type>
+	_Parameter(const _Type& __inst, const char* __name, _Is_instance)
+	: _M_kind(__instance), _M_variant()
+	{
+	  _M_variant._M_instance._M_name = __name;
+	  _M_variant._M_instance._M_address = &__inst;
+	  _M_variant._M_instance._M_type = _GLIBCXX_TYPEID(_Type);
+	}
+
       void
       _M_print_field(const _Error_formatter* __formatter,
 		     const char* __name) const;
@@ -347,9 +380,6 @@ 
       _M_print_description(const _Error_formatter* __formatter) const;
     };
 
-    friend struct _Parameter;
-
-  public:
     template<typename _Iterator>
       const _Error_formatter&
       _M_iterator(const _Iterator& __it, const char* __name = 0)  const
@@ -360,6 +390,17 @@ 
 	return *this;
       }
 
+    template<typename _Iterator>
+      const _Error_formatter&
+      _M_iterator_value_type(const _Iterator& __it,
+			     const char* __name = 0)  const
+      {
+	if (_M_num_parameters < std::size_t(__max_parameters))
+	  _M_parameters[_M_num_parameters++] =
+	    _Parameter(__it, __name, _Is_iterator_value_type());
+	return *this;
+      }
+
     const _Error_formatter&
     _M_integer(long __value, const char* __name = 0) const
     {
@@ -386,6 +427,16 @@ 
 	return *this;
       }
 
+    template<typename _Type>
+      const _Error_formatter&
+      _M_instance(const _Type& __inst, const char* __name = 0) const
+      {
+	if (_M_num_parameters < std::size_t(__max_parameters))
+	  _M_parameters[_M_num_parameters++] = _Parameter(__inst, __name,
+							  _Is_instance());
+	return *this;
+      }
+
     const _Error_formatter&
     _M_message(const char* __text) const
     { _M_text = __text; return *this; }
@@ -396,12 +447,6 @@ 
     _GLIBCXX_NORETURN void
     _M_error() const;
 
-  private:
-    _Error_formatter(const char* __file, std::size_t __line)
-    : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0),
-      _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false)
-    { _M_get_max_length(); }
-
     template<typename _Tp>
       void
       _M_format_word(char*, int, const char*, _Tp) const throw ();
@@ -412,9 +457,11 @@ 
     void
     _M_print_string(const char* __string) const;
 
-    void
-    _M_print_type(const type_info* __info,
-		  const char* __unknown_name) const;
+  private:
+    _Error_formatter(const char* __file, std::size_t __line)
+    : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0),
+      _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false)
+    { _M_get_max_length(); }
 
     void
     _M_get_max_length() const throw ();
Index: include/debug/forward_list
===================================================================
--- include/debug/forward_list	(revision 223630)
+++ include/debug/forward_list	(working copy)
@@ -824,4 +824,6 @@ 
 #endif
 }
 
+#include <debug/functions.tcc>
+
 #endif
Index: include/debug/functions.h
===================================================================
--- include/debug/functions.h	(revision 223630)
+++ include/debug/functions.h	(working copy)
@@ -33,11 +33,7 @@ 
 #include <bits/stl_iterator_base_types.h> // for iterator_traits, categories and
 					  // _Iter_base
 #include <bits/cpp_type_traits.h>	  // for __is_integer
-#include <bits/move.h>                    // for __addressof and addressof
-#include <bits/stl_function.h>		  // for less
-#if __cplusplus >= 201103L
-# include <type_traits>			  // for is_lvalue_reference and __and_
-#endif
+
 #include <debug/formatter.h>
 
 namespace __gnu_debug
@@ -45,9 +41,6 @@ 
   template<typename _Iterator, typename _Sequence>
     class _Safe_iterator;
 
-  template<typename _Iterator, typename _Sequence>
-    class _Safe_local_iterator;
-
   template<typename _Sequence>
     struct _Insert_range_from_self_is_safe
     { enum { __value = 0 }; };
@@ -85,19 +78,6 @@ 
     __check_dereferenceable(const _Tp* __ptr)
     { return __ptr; }
 
-  /** Safe iterators know if they are dereferenceable. */
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    __check_dereferenceable(const _Safe_iterator<_Iterator, _Sequence>& __x)
-    { return __x._M_dereferenceable(); }
-
-  /** Safe local iterators know if they are dereferenceable. */
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    __check_dereferenceable(const _Safe_local_iterator<_Iterator,
-						       _Sequence>& __x)
-    { return __x._M_dereferenceable(); }
-
   /** If the distance between two random access iterators is
    *  nonnegative, assume the range is valid.
   */
@@ -150,20 +130,6 @@ 
       return __valid_range_aux(__first, __last, _Integral());
     }
 
-  /** Safe iterators know how to check if they form a valid range. */
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    __valid_range(const _Safe_iterator<_Iterator, _Sequence>& __first,
-		  const _Safe_iterator<_Iterator, _Sequence>& __last)
-    { return __first._M_valid_range(__last); }
-
-  /** Safe local iterators know how to check if they form a valid range. */
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first,
-		  const _Safe_local_iterator<_Iterator, _Sequence>& __last)
-    { return __first._M_valid_range(__last); }
-
   /* Checks that [first, last) is a valid range, and then returns
    * __first. This routine is useful when we can't use a separate
    * assertion statement because, e.g., we are in a constructor.
@@ -178,121 +144,11 @@ 
       return __first;
     }
 
-  /* Handle the case where __other is a pointer to _Sequence::value_type. */
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    __foreign_iterator_aux4(const _Safe_iterator<_Iterator, _Sequence>& __it,
-			    const typename _Sequence::value_type* __other)
-    {
-      typedef const typename _Sequence::value_type* _PointerType;
-      typedef std::less<_PointerType> _Less;
-#if __cplusplus >= 201103L
-      constexpr _Less __l{};
-#else
-      const _Less __l = _Less();
-#endif
-      const _Sequence* __seq = __it._M_get_sequence();
-      const _PointerType __begin = std::__addressof(*__seq->_M_base().begin());
-      const _PointerType __end = std::__addressof(*(__seq->_M_base().end()-1));
-
-      // Check whether __other points within the contiguous storage.
-      return __l(__other, __begin) || __l(__end, __other);
-    }
-
-  /* Fallback overload for when we can't tell, assume it is valid. */
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    __foreign_iterator_aux4(const _Safe_iterator<_Iterator, _Sequence>&, ...)
-    { return true; }
-
-  /* Handle sequences with contiguous storage */
-  template<typename _Iterator, typename _Sequence, typename _InputIterator>
-    inline bool
-    __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>& __it,
-			    const _InputIterator& __other,
-			    const _InputIterator& __other_end,
-			    std::__true_type)
-    {
-      if (__other == __other_end)
-	return true;  // inserting nothing is safe even if not foreign iters
-      if (__it._M_get_sequence()->begin() == __it._M_get_sequence()->end())
-	return true;  // can't be self-inserting if self is empty
-      return __foreign_iterator_aux4(__it, std::__addressof(*__other));
-    }
-
-  /* Handle non-contiguous containers, assume it is valid. */
-  template<typename _Iterator, typename _Sequence, typename _InputIterator>
-    inline bool
-    __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>&,
-			    const _InputIterator&, const _InputIterator&,
-			    std::__false_type)
-    { return true; }
-
-  /** Handle debug iterators from the same type of container. */
-  template<typename _Iterator, typename _Sequence, typename _OtherIterator>
-    inline bool
-    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
-		const _Safe_iterator<_OtherIterator, _Sequence>& __other,
-		const _Safe_iterator<_OtherIterator, _Sequence>&)
-    { return __it._M_get_sequence() != __other._M_get_sequence(); }
-
-  /** Handle debug iterators from different types of container. */
-  template<typename _Iterator, typename _Sequence, typename _OtherIterator,
-	   typename _OtherSequence>
-    inline bool
-    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
-		const _Safe_iterator<_OtherIterator, _OtherSequence>&,
-		const _Safe_iterator<_OtherIterator, _OtherSequence>&)
-    { return true; }
-
-  /* Handle non-debug iterators. */
-  template<typename _Iterator, typename _Sequence, typename _InputIterator>
-    inline bool
-    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
-			    const _InputIterator& __other,
-			    const _InputIterator& __other_end)
-    {
-#if __cplusplus < 201103L
-      typedef _Is_contiguous_sequence<_Sequence> __tag;
-#else
-      using __lvalref = std::is_lvalue_reference<
-	typename std::iterator_traits<_InputIterator>::reference>;
-      using __contiguous = _Is_contiguous_sequence<_Sequence>;
-      using __tag = typename std::conditional<__lvalref::value, __contiguous,
-					      std::__false_type>::type;
-#endif
-      return __foreign_iterator_aux3(__it, __other, __other_end, __tag());
-    }
-
-  /* Handle the case where we aren't really inserting a range after all */
-  template<typename _Iterator, typename _Sequence, typename _Integral>
-    inline bool
-    __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>&,
-			   _Integral, _Integral,
-			   std::__true_type)
-    { return true; }
-
-  /* Handle all iterators. */
   template<typename _Iterator, typename _Sequence,
 	   typename _InputIterator>
-    inline bool
-    __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>& __it,
-			   _InputIterator __other, _InputIterator __other_end,
-			   std::__false_type)
-    {
-      return _Insert_range_from_self_is_safe<_Sequence>::__value
-	     || __foreign_iterator_aux2(__it, __other, __other_end);
-    }
-
-  template<typename _Iterator, typename _Sequence,
-	   typename _InputIterator>
-    inline bool
+    bool
     __foreign_iterator(const _Safe_iterator<_Iterator, _Sequence>& __it,
-		       _InputIterator __other, _InputIterator __other_end)
-    {
-      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
-      return __foreign_iterator_aux(__it, __other, __other_end, _Integral());
-    }
+		       _InputIterator __other, _InputIterator __other_end);
 
   /** Checks that __s is non-NULL or __n == 0, and then returns __s. */
   template<typename _CharT, typename _Integer>
@@ -535,13 +391,6 @@ 
       typedef std::__false_type __type;
     };
 
-  template<typename _Iterator, typename _Sequence>
-    struct __is_safe_random_iterator<_Safe_iterator<_Iterator, _Sequence> >
-    : std::__are_same<std::random_access_iterator_tag,
-                      typename std::iterator_traits<_Iterator>::
-		      iterator_category>
-    { };
-
   template<typename _Iterator>
     struct _Siter_base
     : std::_Iter_base<_Iterator, __is_safe_random_iterator<_Iterator>::__value>
Index: include/debug/functions.tcc
===================================================================
--- include/debug/functions.tcc	(revision 0)
+++ include/debug/functions.tcc	(working copy)
@@ -0,0 +1,159 @@ 
+// Debugging support implementation -*- C++ -*-
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file debug/functions.tcc
+ *  This file is a GNU debug extension to the Standard C++ Library.
+ */
+
+#ifndef _GLIBCXX_DEBUG_FUNCTIONS_TCC
+#define _GLIBCXX_DEBUG_FUNCTIONS_TCC 1
+
+#include <bits/move.h>			// for __addressof and addressof
+#include <bits/stl_function.h>		// for less
+#if __cplusplus >= 201103L
+# include <type_traits>			// for is_lvalue_reference
+					// conditional.
+#endif
+
+namespace __gnu_debug
+{
+  /* Handle the case where __other is a pointer to _Sequence::value_type. */
+  template<typename _Iterator, typename _Sequence>
+    inline bool
+    __foreign_iterator_aux4(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			    const typename _Sequence::value_type* __other)
+    {
+      typedef const typename _Sequence::value_type* _PointerType;
+      typedef std::less<_PointerType> _Less;
+#if __cplusplus >= 201103L
+      constexpr _Less __l{};
+#else
+      const _Less __l = _Less();
+#endif
+      const _Sequence* __seq = __it._M_get_sequence();
+      const _PointerType __begin = std::__addressof(*__seq->_M_base().begin());
+      const _PointerType __end = std::__addressof(*(__seq->_M_base().end()-1));
+
+      // Check whether __other points within the contiguous storage.
+      return __l(__other, __begin) || __l(__end, __other);
+    }
+
+  /* Fallback overload for when we can't tell, assume it is valid. */
+  template<typename _Iterator, typename _Sequence>
+    inline bool
+    __foreign_iterator_aux4(const _Safe_iterator<_Iterator, _Sequence>&, ...)
+    { return true; }
+
+  /* Handle sequences with contiguous storage */
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			    const _InputIterator& __other,
+			    const _InputIterator& __other_end,
+			    std::__true_type)
+    {
+      if (__other == __other_end)
+	return true;  // inserting nothing is safe even if not foreign iters
+      if (__it._M_get_sequence()->begin() == __it._M_get_sequence()->end())
+	return true;  // can't be self-inserting if self is empty
+      return __foreign_iterator_aux4(__it, std::__addressof(*__other));
+    }
+
+  /* Handle non-contiguous containers, assume it is valid. */
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>&,
+			    const _InputIterator&, const _InputIterator&,
+			    std::__false_type)
+    { return true; }
+
+  /** Handle debug iterators from the same type of container. */
+  template<typename _Iterator, typename _Sequence, typename _OtherIterator>
+    inline bool
+    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
+		const _Safe_iterator<_OtherIterator, _Sequence>& __other,
+		const _Safe_iterator<_OtherIterator, _Sequence>&)
+    { return __it._M_get_sequence() != __other._M_get_sequence(); }
+
+  /** Handle debug iterators from different types of container. */
+  template<typename _Iterator, typename _Sequence, typename _OtherIterator,
+	   typename _OtherSequence>
+    inline bool
+    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
+		const _Safe_iterator<_OtherIterator, _OtherSequence>&,
+		const _Safe_iterator<_OtherIterator, _OtherSequence>&)
+    { return true; }
+
+  /* Handle non-debug iterators. */
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			    const _InputIterator& __other,
+			    const _InputIterator& __other_end)
+    {
+#if __cplusplus < 201103L
+      typedef _Is_contiguous_sequence<_Sequence> __tag;
+#else
+      using __lvalref = std::is_lvalue_reference<
+	typename std::iterator_traits<_InputIterator>::reference>;
+      using __contiguous = _Is_contiguous_sequence<_Sequence>;
+      using __tag = typename std::conditional<__lvalref::value, __contiguous,
+					      std::__false_type>::type;
+#endif
+      return __foreign_iterator_aux3(__it, __other, __other_end, __tag());
+    }
+
+  /* Handle the case where we aren't really inserting a range after all */
+  template<typename _Iterator, typename _Sequence, typename _Integral>
+    inline bool
+    __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>&,
+			   _Integral, _Integral,
+			   std::__true_type)
+    { return true; }
+
+  /* Handle all iterators. */
+  template<typename _Iterator, typename _Sequence,
+	   typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			   _InputIterator __other, _InputIterator __other_end,
+			   std::__false_type)
+    {
+      return _Insert_range_from_self_is_safe<_Sequence>::__value
+	     || __foreign_iterator_aux2(__it, __other, __other_end);
+    }
+
+  template<typename _Iterator, typename _Sequence,
+	   typename _InputIterator>
+    inline bool
+    __foreign_iterator(const _Safe_iterator<_Iterator, _Sequence>& __it,
+		       _InputIterator __other, _InputIterator __other_end)
+    {
+      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
+      return __foreign_iterator_aux(__it, __other, __other_end, _Integral());
+    }
+
+} // namespace __gnu_debug
+
+#endif
Index: include/debug/list
===================================================================
--- include/debug/list	(revision 223630)
+++ include/debug/list	(working copy)
@@ -797,4 +797,6 @@ 
 }
 #endif
 
+#include <debug/functions.tcc>
+
 #endif
Index: include/debug/safe_base.h
===================================================================
--- include/debug/safe_base.h	(revision 223630)
+++ include/debug/safe_base.h	(working copy)
@@ -159,6 +159,13 @@ 
     }
   };
 
+  /** Iterators that derive from _Safe_iterator_base can be determined singular
+   *  or non-singular.
+   **/
+  inline bool
+  __check_singular_aux(const _Safe_iterator_base* __x)
+  { return __x->_M_singular(); }
+
   /**
    * @brief Base class that supports tracking of iterators that
    * reference a sequence.
Index: include/debug/safe_iterator.h
===================================================================
--- include/debug/safe_iterator.h	(revision 223630)
+++ include/debug/safe_iterator.h	(working copy)
@@ -29,7 +29,7 @@ 
 #ifndef _GLIBCXX_DEBUG_SAFE_ITERATOR_H
 #define _GLIBCXX_DEBUG_SAFE_ITERATOR_H 1
 
-#include <debug/debug.h>
+#include <debug/assertions.h>
 #include <debug/macros.h>
 #include <debug/functions.h>
 #include <debug/safe_base.h>
@@ -55,13 +55,6 @@ 
 	{ return __it.base() == __it._M_get_sequence()->_M_base().begin(); }
     };
 
-  /** Iterators that derive from _Safe_iterator_base can be determined singular
-   *  or non-singular.
-   **/
-  inline bool
-  __check_singular_aux(const _Safe_iterator_base* __x)
-  { return __x->_M_singular(); }
-
   /** The precision to which we can calculate the distance between
    *  two iterators.
    */
@@ -93,11 +86,7 @@ 
     inline std::pair<typename std::iterator_traits<_Iterator>::difference_type,
 		     _Distance_precision>
     __get_distance(const _Iterator& __lhs, const _Iterator& __rhs)
-    {
-      typedef typename std::iterator_traits<_Iterator>::iterator_category
-	  _Category;
-      return __get_distance(__lhs, __rhs, _Category());
-    }
+    { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); }
 
   /** \brief Safe iterator wrapper.
    *
@@ -768,6 +757,27 @@ 
     operator+(typename _Safe_iterator<_Iterator,_Sequence>::difference_type __n,
 	      const _Safe_iterator<_Iterator, _Sequence>& __i) _GLIBCXX_NOEXCEPT
     { return __i + __n; }
+
+  /** Safe iterators know if they are dereferenceable. */
+  template<typename _Iterator, typename _Sequence>
+    inline bool
+    __check_dereferenceable(const _Safe_iterator<_Iterator, _Sequence>& __x)
+    { return __x._M_dereferenceable(); }
+
+  /** Safe iterators know how to check if they form a valid range. */
+  template<typename _Iterator, typename _Sequence>
+    inline bool
+    __valid_range(const _Safe_iterator<_Iterator, _Sequence>& __first,
+		  const _Safe_iterator<_Iterator, _Sequence>& __last)
+    { return __first._M_valid_range(__last); }
+
+  template<typename _Iterator, typename _Sequence>
+    struct __is_safe_random_iterator<_Safe_iterator<_Iterator, _Sequence> >
+    : std::__are_same<std::random_access_iterator_tag,
+                      typename std::iterator_traits<_Iterator>::
+		      iterator_category>
+    { };
+
 } // namespace __gnu_debug
 
 #include <debug/safe_iterator.tcc>
Index: include/debug/safe_local_iterator.h
===================================================================
--- include/debug/safe_local_iterator.h	(revision 223630)
+++ include/debug/safe_local_iterator.h	(working copy)
@@ -29,11 +29,7 @@ 
 #ifndef _GLIBCXX_DEBUG_SAFE_LOCAL_ITERATOR_H
 #define _GLIBCXX_DEBUG_SAFE_LOCAL_ITERATOR_H 1
 
-#include <debug/debug.h>
-#include <debug/macros.h>
-#include <debug/functions.h>
 #include <debug/safe_unordered_base.h>
-#include <ext/type_traits.h>
 
 namespace __gnu_debug
 {
@@ -432,6 +428,20 @@ 
 			    ._M_iterator(__rhs, "rhs"));
       return __lhs.base() != __rhs.base();
     }
+
+  /** Safe local iterators know if they are dereferenceable. */
+  template<typename _Iterator, typename _Sequence>
+    inline bool
+    __check_dereferenceable(const _Safe_local_iterator<_Iterator,
+						       _Sequence>& __x)
+    { return __x._M_dereferenceable(); }
+
+  /** Safe local iterators know how to check if they form a valid range. */
+  template<typename _Iterator, typename _Sequence>
+    inline bool
+    __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first,
+		  const _Safe_local_iterator<_Iterator, _Sequence>& __last)
+    { return __first._M_valid_range(__last); }
 } // namespace __gnu_debug
 
 #include <debug/safe_local_iterator.tcc>
Index: include/debug/safe_sequence.h
===================================================================
--- include/debug/safe_sequence.h	(revision 223630)
+++ include/debug/safe_sequence.h	(working copy)
@@ -29,7 +29,7 @@ 
 #ifndef _GLIBCXX_DEBUG_SAFE_SEQUENCE_H
 #define _GLIBCXX_DEBUG_SAFE_SEQUENCE_H 1
 
-#include <debug/debug.h>
+#include <debug/assertions.h>
 #include <debug/macros.h>
 #include <debug/functions.h>
 #include <debug/safe_base.h>
@@ -36,9 +36,6 @@ 
 
 namespace __gnu_debug
 {
-  template<typename _Iterator, typename _Sequence>
-    class _Safe_iterator;
-
   /** A simple function object that returns true if the passed-in
    *  value is not equal to the stored value. It saves typing over
    *  using both bind1st and not_equal.
Index: include/debug/safe_unordered_container.h
===================================================================
--- include/debug/safe_unordered_container.h	(revision 223630)
+++ include/debug/safe_unordered_container.h	(working copy)
@@ -29,7 +29,7 @@ 
 #ifndef _GLIBCXX_DEBUG_SAFE_UNORDERED_CONTAINER_H
 #define _GLIBCXX_DEBUG_SAFE_UNORDERED_CONTAINER_H 1
 
-#include <debug/debug.h>
+#include <debug/assertions.h>
 #include <debug/macros.h>
 #include <debug/functions.h>
 #include <debug/safe_unordered_base.h>
Index: include/debug/string
===================================================================
--- include/debug/string	(revision 223630)
+++ include/debug/string	(working copy)
@@ -1158,4 +1158,6 @@ 
 
 } // namespace __gnu_debug
 
+#include <debug/functions.tcc>
+
 #endif
Index: include/debug/vector
===================================================================
--- include/debug/vector	(revision 223630)
+++ include/debug/vector	(working copy)
@@ -742,8 +742,7 @@ 
     {
       size_t
       operator()(const __debug::vector<bool, _Alloc>& __b) const noexcept
-      { return std::hash<_GLIBCXX_STD_C::vector<bool, _Alloc>>()
-	  (__b._M_base()); }
+      { return std::hash<_GLIBCXX_STD_C::vector<bool, _Alloc>>()(__b); }
     };
 #endif
 
@@ -762,4 +761,6 @@ 
     { };
 }
 
+#include <debug/functions.tcc>
+
 #endif
Index: src/c++11/debug.cc
===================================================================
--- src/c++11/debug.cc	(revision 223630)
+++ src/c++11/debug.cc	(working copy)
@@ -519,8 +519,123 @@ 
     if (_M_local_iterators == __it)
       _M_local_iterators = __it->_M_next;
   }
+}
 
+namespace
+{
   void
+  print_type(const __gnu_debug::_Error_formatter* __formatter,
+	     const type_info* __info,
+	     const char* __unknown_name)
+  {
+    if (!__info)
+      __formatter->_M_print_word(__unknown_name);
+    else
+      {
+	int __status;
+	char* __demangled_name =
+	  __cxxabiv1::__cxa_demangle(__info->name(), NULL, NULL, &__status);
+	__formatter->_M_print_word(__status == 0
+				   ? __demangled_name : __info->name());
+	free(__demangled_name);
+      }
+  }
+
+  bool
+  print_field(
+    const __gnu_debug::_Error_formatter* __formatter,
+    const char* __name,
+    const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
+  {
+    if (strcmp(__name, "name") == 0)
+      {
+	assert(__variant._M_name);
+	__formatter->_M_print_word(__variant._M_name);
+      }
+    else if (strcmp(__name, "type") == 0)
+      print_type(__formatter, __variant._M_type, "<unknown type>");
+    else
+      return false;
+
+    return true;
+  }
+
+  bool
+  print_field(
+    const __gnu_debug::_Error_formatter* __formatter,
+    const char* __name,
+    const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  {
+    const __gnu_debug::_Error_formatter::_Parameter::_Type& __type = __variant;
+    if (print_field(__formatter, __name, __type))
+      { }
+    else if (strcmp(__name, "address") == 0)
+      {
+	const int __bufsize = 64;
+	char __buf[__bufsize];
+	__formatter->_M_format_word(__buf, __bufsize, "%p",
+				    __variant._M_address);
+	__formatter->_M_print_word(__buf);
+      }
+    else
+      return false;
+
+    return true;
+  }
+
+  void
+  print_description(
+	const __gnu_debug::_Error_formatter* __formatter,
+	const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
+  {
+    if (__variant._M_name)
+      {
+	const int __bufsize = 64;
+	char __buf[__bufsize];
+	__formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
+				    __variant._M_name);
+	__formatter->_M_print_word(__buf);
+      }
+
+    if (__variant._M_type)
+      {
+	__formatter->_M_print_word("  type = ");
+	print_type(__formatter, __variant._M_type, "<unknown type>");
+	__formatter->_M_print_word(";\n");
+      }
+  }
+
+
+  void
+  print_description(
+	const __gnu_debug::_Error_formatter* __formatter,
+	const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  {
+    const int __bufsize = 64;
+    char __buf[__bufsize];
+
+    if (__variant._M_name)
+      {
+	__formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
+				    __variant._M_name);
+	__formatter->_M_print_word(__buf);
+      }
+
+    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
+				__variant._M_address);
+    __formatter->_M_print_word(__buf);
+
+    if (__variant._M_type)
+      {
+	__formatter->_M_print_word("  type = ");
+	print_type(__formatter, __variant._M_type, "<unknown type>");
+      }
+  }
+}
+
+namespace __gnu_debug
+{
+  void
   _Error_formatter::_Parameter::
   _M_print_field(const _Error_formatter* __formatter, const char* __name) const
   {
@@ -531,20 +646,8 @@ 
     switch (_M_kind)
     {
     case __iterator:
-      if (strcmp(__name, "name") == 0)
-	{
-	  assert(_M_variant._M_iterator._M_name);
-	  __formatter->_M_print_word(_M_variant._M_iterator._M_name);
-	}
-      else if (strcmp(__name, "address") == 0)
-	{
-	  __formatter->_M_format_word(__buf, __bufsize, "%p",
-				      _M_variant._M_iterator._M_address);
-	  __formatter->_M_print_word(__buf);
-	}
-      else if (strcmp(__name, "type") == 0)
-	__formatter->_M_print_type(_M_variant._M_iterator._M_type,
-				   "<unknown type>");
+      if (print_field(__formatter, __name, _M_variant._M_iterator))
+	{ }
       else if (strcmp(__name, "constness") == 0)
 	{
 	  static const char* __constness_names[__last_constness] =
@@ -579,28 +682,13 @@ 
 	  __formatter->_M_print_word(__buf);
 	}
       else if (strcmp(__name, "seq_type") == 0)
-	__formatter->_M_print_type(_M_variant._M_iterator._M_seq_type,
-				   "<unknown seq_type>");
+	print_type(__formatter, _M_variant._M_iterator._M_seq_type,
+		   "<unknown seq_type>");
       else
 	assert(false);
       break;
     case __sequence:
-      if (strcmp(__name, "name") == 0)
-	{
-	  assert(_M_variant._M_sequence._M_name);
-	  __formatter->_M_print_word(_M_variant._M_sequence._M_name);
-	}
-      else if (strcmp(__name, "address") == 0)
-	{
-	  assert(_M_variant._M_sequence._M_address);
-	  __formatter->_M_format_word(__buf, __bufsize, "%p",
-				      _M_variant._M_sequence._M_address);
-	  __formatter->_M_print_word(__buf);
-	}
-      else if (strcmp(__name, "type") == 0)
-	__formatter->_M_print_type(_M_variant._M_sequence._M_type,
-				   "<unknown type>");
-      else
+      if (!print_field(__formatter, __name, _M_variant._M_sequence))
 	assert(false);
       break;
     case __integer:
@@ -621,6 +709,14 @@ 
       else
 	assert(false);
       break;
+    case __instance:
+      if (!print_field(__formatter, __name, _M_variant._M_instance))
+	assert(false);
+      break;
+    case __iterator_value_type:
+      if (!print_field(__formatter, __name, _M_variant._M_iterator_value_type))
+	assert(false);
+      break;
     default:
       assert(false);
       break;
@@ -638,21 +734,10 @@ 
       {
       case __iterator:
 	__formatter->_M_print_word("iterator ");
-	if (_M_variant._M_iterator._M_name)
-	  {
-	    __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
-					_M_variant._M_iterator._M_name);
-	    __formatter->_M_print_word(__buf);
-	  }
+	print_description(__formatter, _M_variant._M_iterator);
 
-	__formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
-				    _M_variant._M_iterator._M_address);
-	__formatter->_M_print_word(__buf);
 	if (_M_variant._M_iterator._M_type)
 	  {
-	    __formatter->_M_print_word("type = ");
-	    _M_print_field(__formatter, "type");
-
 	    if (_M_variant._M_iterator._M_constness != __unknown_constness)
 	      {
 		__formatter->_M_print_word(" (");
@@ -687,25 +772,25 @@ 
 	break;
       case __sequence:
 	__formatter->_M_print_word("sequence ");
-	if (_M_variant._M_sequence._M_name)
-	  {
-	    __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
-					_M_variant._M_sequence._M_name);
-	    __formatter->_M_print_word(__buf);
-	  }
+	print_description(__formatter, _M_variant._M_sequence);
 
-	__formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
-				    _M_variant._M_sequence._M_address);
-	__formatter->_M_print_word(__buf);
+	if (_M_variant._M_sequence._M_type)
+	  __formatter->_M_print_word(";\n");
 
-	if (_M_variant._M_sequence._M_type)
-	  {
-	    __formatter->_M_print_word("  type = ");
-	    _M_print_field(__formatter, "type");
-	    __formatter->_M_print_word(";\n");
-	  }
 	__formatter->_M_print_word("}\n");
 	break;
+      case __instance:
+	__formatter->_M_print_word("instance ");
+	print_description(__formatter, _M_variant._M_instance);
+
+	if (_M_variant._M_instance._M_type)
+	  __formatter->_M_print_word(";\n");
+
+	break;
+      case __iterator_value_type:
+	__formatter->_M_print_word("iterator::value_type ");
+	print_description(__formatter, _M_variant._M_iterator_value_type);
+	break;
       default:
 	break;
       }
@@ -756,6 +841,8 @@ 
 	  {
 	  case _Parameter::__iterator:
 	  case _Parameter::__sequence:
+	  case _Parameter::__instance:
+	  case _Parameter::__iterator_value_type:
 	    if (!__has_noninteger_parameters)
 	      {
 		_M_first_line = true;
@@ -879,9 +966,9 @@ 
 
 	// Get the parameter number
 	assert(*__start >= '1' && *__start <= '9');
-	size_t __param = *__start - '0';
-	--__param;
-	assert(__param < _M_num_parameters);
+	size_t __param_index = *__start - '0' - 1;
+	assert(__param_index < _M_num_parameters);
+	const auto& __param = _M_parameters[__param_index];
 
 	// '.' separates the parameter number from the field
 	// name, if there is one.
@@ -891,14 +978,14 @@ 
 	    assert(*__start == ';');
 	    ++__start;
 	    __buf[0] = '\0';
-	    if (_M_parameters[__param]._M_kind == _Parameter::__integer)
+	    if (__param._M_kind == _Parameter::__integer)
 	      {
 		_M_format_word(__buf, __bufsize, "%ld",
-			       _M_parameters[__param]._M_variant._M_integer._M_value);
+			       __param._M_variant._M_integer._M_value);
 		_M_print_word(__buf);
 	      }
-	    else if (_M_parameters[__param]._M_kind == _Parameter::__string)
-	      _M_print_string(_M_parameters[__param]._M_variant._M_string._M_value);
+	    else if (__param._M_kind == _Parameter::__string)
+	      _M_print_string(__param._M_variant._M_string._M_value);
 	    continue;
 	  }
 
@@ -916,27 +1003,11 @@ 
 	++__start;
 	__field[__field_idx] = 0;
 
-	_M_parameters[__param]._M_print_field(this, __field);
+	__param._M_print_field(this, __field);
       }
   }
 
   void
-  _Error_formatter::_M_print_type(const type_info* __info,
-				  const char* __unknown_name) const
-  {
-    if (!__info)
-      _M_print_word(__unknown_name);
-    else
-      {
-	int __status;
-	char* __demangled_name =
-	  __cxxabiv1::__cxa_demangle(__info->name(), NULL, NULL, &__status);
-	_M_print_word(__status == 0 ? __demangled_name : __info->name());
-	free(__demangled_name);
-      }
-  }
-
-  void
   _Error_formatter::_M_get_max_length() const throw ()
   {
     const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
Index: testsuite/23_containers/array/tuple_interface/get_debug_neg.cc
===================================================================
--- testsuite/23_containers/array/tuple_interface/get_debug_neg.cc	(revision 223630)
+++ testsuite/23_containers/array/tuple_interface/get_debug_neg.cc	(working copy)
@@ -28,6 +28,6 @@ 
 int n2 = std::get<1>(std::move(a));
 int n3 = std::get<1>(ca);
 
-// { dg-error "static assertion failed" "" { target *-*-* } 271 }
-// { dg-error "static assertion failed" "" { target *-*-* } 280 }
-// { dg-error "static assertion failed" "" { target *-*-* } 288 }
+// { dg-error "static assertion failed" "" { target *-*-* } 272 }
+// { dg-error "static assertion failed" "" { target *-*-* } 281 }
+// { dg-error "static assertion failed" "" { target *-*-* } 289 }
Index: testsuite/23_containers/array/tuple_interface/tuple_element_debug_neg.cc
===================================================================
--- testsuite/23_containers/array/tuple_interface/tuple_element_debug_neg.cc	(revision 223630)
+++ testsuite/23_containers/array/tuple_interface/tuple_element_debug_neg.cc	(working copy)
@@ -23,4 +23,4 @@ 
 
 typedef std::tuple_element<1, std::array<int, 1>>::type type;
 
-// { dg-error "static assertion failed" "" { target *-*-* } 305 }
+// { dg-error "static assertion failed" "" { target *-*-* } 306 }