public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* debug mode symbols cleanup
@ 2015-09-05 21:02 François Dumont
  2015-09-07 11:04 ` Jonathan Wakely
  2015-09-18 11:06 ` Ulrich Weigand
  0 siblings, 2 replies; 9+ messages in thread
From: François Dumont @ 2015-09-05 21:02 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1316 bytes --]

Hi

    I wanted to enhance line wrapping during rendering of debug messages
and ended up with this patch.

    I clean up _Error_formatter of all useless symbols, only _M_message
and _M_error need to be exposed. Additional I got rid  of the ugly
mutable fields of _Error_formatter. _Error_formatter instance in _M_at
method can be made static because we only create an instance when we
detect an issue so just before application abort.

    I remember Paolo saying once that we were not guarantiing any abi
compatibility for debug mode. I haven't found any section for
unversioned symbols in gnu.ver so I simply uncomment the global export.

Tested under Linux x86_64.

    * include/debug/formatter.h
    (_Error_formatter::_Parameter::_M_print_field): Delete.
    (_Error_formatter::_Parameter::_M_print_description): Likewise.
    (_Error_formatter::_M_format_word): Likewise.
    (_Error_formatter::_M_print_word): Likewise.
    (_Error_formatter::_M_print_string): Likewise.
    (_Error_formatter::_M_get_max_length): Likewise.
    (_Error_formatter::_M_max_length): Likewise.
    (_Error_formatter::_M_indent): Likewise.
    (_Error_formatter::_M_column): Likewise.
    (_Error_formatter::_M_first_line): Likewise.
    (_Error_formatter::_M_wordwrap): Likewise.
    * src/c++11/debug.cc: Adapt.

François


[-- Attachment #2: debug.patch --]
[-- Type: text/x-patch, Size: 32947 bytes --]

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 8f9f99a..6d57cab 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -194,7 +194,7 @@ GLIBCXX_3.4 {
       std::__moneypunct_cache*;
       std::__numpunct_cache*;
       std::__timepunct_cache*;
-#     __gnu_debug::_Error_formatter*
+      __gnu_debug::_Error_formatter*
     };
 
     # Names not in an 'extern' block are mangled names.  Character classes
@@ -687,13 +687,6 @@ GLIBCXX_3.4 {
     _ZNK11__gnu_debug19_Safe_iterator_base11_M_singularEv;
     _ZNK11__gnu_debug19_Safe_iterator_base14_M_can_compareERKS0_;
 
-    # __gnu_debug::_Error_formatter
-    _ZNK11__gnu_debug16_Error_formatter10_M_message*;
-    _ZNK11__gnu_debug16_Error_formatter10_Parameter*;
-    _ZNK11__gnu_debug16_Error_formatter13_M_print_word*;
-    _ZNK11__gnu_debug16_Error_formatter15_M_print_string*;
-    _ZNK11__gnu_debug16_Error_formatter8_M_error*;
-
     # exceptions as functions
     _ZSt16__throw_bad_castv;
     _ZSt17__throw_bad_allocv;
@@ -1185,8 +1178,6 @@ GLIBCXX_3.4.9 {
 
 GLIBCXX_3.4.10 {
 
-    _ZNK11__gnu_debug16_Error_formatter17_M_get_max_lengthEv;
-
     _ZNKSt3tr14hashIRKSbIwSt11char_traitsIwESaIwEEEclES6_;
     _ZNKSt3tr14hashIRKSsEclES2_;
     _ZNKSt3tr14hashISbIwSt11char_traitsIwESaIwEEEclES4_;
diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h
index f0ac694..e22247c 100644
--- a/libstdc++-v3/include/debug/formatter.h
+++ b/libstdc++-v3/include/debug/formatter.h
@@ -133,6 +133,13 @@ namespace __gnu_debug
 
   class _Error_formatter
   {
+    // Tags denoting the type of parameter for construction
+    struct _Is_iterator { };
+    struct _Is_iterator_value_type { };
+    struct _Is_sequence { };
+    struct _Is_instance { };
+
+  public:
     /// Whether an iterator is constant, mutable, or unknown
     enum _Constness
     {
@@ -154,13 +161,6 @@ namespace __gnu_debug
       __last_state
     };
 
-    // 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
     {
@@ -373,18 +373,11 @@ namespace __gnu_debug
 	  _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;
-
-      void
-      _M_print_description(const _Error_formatter* __formatter) const;
     };
 
     template<typename _Iterator>
-      const _Error_formatter&
-      _M_iterator(const _Iterator& __it, const char* __name = 0)  const
+      _Error_formatter&
+      _M_iterator(const _Iterator& __it, const char* __name = 0)
       {
 	if (_M_num_parameters < std::size_t(__max_parameters))
 	  _M_parameters[_M_num_parameters++] = _Parameter(__it, __name,
@@ -393,98 +386,82 @@ namespace __gnu_debug
       }
 
     template<typename _Iterator>
-      const _Error_formatter&
+      _Error_formatter&
       _M_iterator_value_type(const _Iterator& __it,
-			     const char* __name = 0)  const
+			     const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __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
+    _Error_formatter&
+    _M_integer(long __value, const char* __name = 0)
     {
-      if (_M_num_parameters < std::size_t(__max_parameters))
+      if (_M_num_parameters < __max_parameters)
 	_M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
       return *this;
     }
 
-    const _Error_formatter&
-    _M_string(const char* __value, const char* __name = 0) const
+    _Error_formatter&
+    _M_string(const char* __value, const char* __name = 0)
     {
-      if (_M_num_parameters < std::size_t(__max_parameters))
+      if (_M_num_parameters < __max_parameters)
 	_M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
       return *this;
     }
 
     template<typename _Sequence>
-      const _Error_formatter&
-      _M_sequence(const _Sequence& __seq, const char* __name = 0) const
+      _Error_formatter&
+      _M_sequence(const _Sequence& __seq, const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __max_parameters)
 	  _M_parameters[_M_num_parameters++] = _Parameter(__seq, __name,
 							  _Is_sequence());
 	return *this;
       }
 
     template<typename _Type>
-      const _Error_formatter&
-      _M_instance(const _Type& __inst, const char* __name = 0) const
+      _Error_formatter&
+      _M_instance(const _Type& __inst, const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __max_parameters)
 	  _M_parameters[_M_num_parameters++] = _Parameter(__inst, __name,
 							  _Is_instance());
 	return *this;
       }
 
-    const _Error_formatter&
-    _M_message(const char* __text) const
+    _Error_formatter&
+    _M_message(const char* __text)
     { _M_text = __text; return *this; }
 
-    const _Error_formatter&
-    _M_message(_Debug_msg_id __id) const throw ();
+    _Error_formatter&
+    _M_message(_Debug_msg_id __id) throw ();
 
     _GLIBCXX_NORETURN void
     _M_error() const;
 
-    template<typename _Tp>
-      void
-      _M_format_word(char*, int, const char*, _Tp) const throw ();
-
-    void
-    _M_print_word(const char* __word) const;
-
-    void
-    _M_print_string(const char* __string) 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 ();
+    _Error_formatter(const char* __file, unsigned int __line)
+    : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0)
+    { }
 
     enum { __max_parameters = 9 };
 
     const char*		_M_file;
-    std::size_t		_M_line;
-    mutable _Parameter	_M_parameters[__max_parameters];
-    mutable std::size_t	_M_num_parameters;
-    mutable const char*	_M_text;
-    mutable std::size_t	_M_max_length;
-    enum { _M_indent = 4 } ;
-    mutable std::size_t	_M_column;
-    mutable bool	_M_first_line;
-    mutable bool	_M_wordwrap;
+    unsigned int	_M_line;
+    _Parameter		_M_parameters[__max_parameters];
+    unsigned int	_M_num_parameters;
+    const char*		_M_text;
 
   public:
-    static _Error_formatter
-    _M_at(const char* __file, std::size_t __line)
-    { return _Error_formatter(__file, __line); }
+    static _Error_formatter&
+    _M_at(const char* __file, unsigned int __line)
+    {
+      static _Error_formatter __formatter(__file, __line);
+      return __formatter;
+    }
   };
 } // namespace __gnu_debug
 
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index d3f8cae..6a41e2c 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -22,18 +22,19 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // <http://www.gnu.org/licenses/>.
 
-#include <debug/debug.h>
+#include <bits/move.h>
+#include <bits/stl_iterator_base_types.h>
+
+#include <debug/formatter.h>
 #include <debug/safe_base.h>
 #include <debug/safe_unordered_base.h>
 #include <debug/safe_iterator.h>
 #include <debug/safe_local_iterator.h>
-#include <algorithm>
+
 #include <cassert>
-#include <cstring>
-#include <cctype>
-#include <cstdio>
-#include <cstdlib>
-#include <functional>
+
+#include <algorithm> // for std::min
+#include <functional> // for _Hash_impl
 
 #include <cxxabi.h> // for __cxa_demangle
 
@@ -526,202 +527,236 @@ namespace __gnu_debug
 
 namespace
 {
+  using _Error_formatter = __gnu_debug::_Error_formatter;
+  using _Parameter = __gnu_debug::_Error_formatter::_Parameter;
+
+  template<typename _Tp>
+    int
+    format_word(char* buf, int n, const char* fmt, _Tp s)
+    { return std::min(__builtin_snprintf(buf, n, fmt, s), n - 1); }
+
   void
-  print_type(const __gnu_debug::_Error_formatter* __formatter,
-	     const type_info* __info,
-	     const char* __unknown_name)
+  get_max_length(std::size_t& max_length)
   {
-    if (!__info)
-      __formatter->_M_print_word(__unknown_name);
-    else
+    const char* nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
+    if (nptr)
       {
-	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);
+	char* endptr;
+	const unsigned long ret = std::strtoul(nptr, &endptr, 0);
+	if (*nptr != '\0' && *endptr == '\0')
+	  max_length = ret;
       }
   }
 
-  bool
-  print_field(
-    const __gnu_debug::_Error_formatter* __formatter,
-    const char* __name,
-    const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
+  struct PrintContext
   {
-    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;
-  }
+    PrintContext()
+      : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false)
+    { get_max_length(_M_max_length); }
+
+    std::size_t	_M_max_length;
+    enum { _M_indent = 4 } ;
+    std::size_t	_M_column;
+    bool	_M_first_line;
+    bool	_M_wordwrap;
+  };
 
-  bool
-  print_field(
-    const __gnu_debug::_Error_formatter* __formatter,
-    const char* __name,
-    const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  void
+  print_word(PrintContext& ctx, const char* word,
+	     std::ptrdiff_t count = -1)
   {
-    const __gnu_debug::_Error_formatter::_Parameter::_Type& __type = __variant;
-    if (print_field(__formatter, __name, __type))
-      { }
-    else if (strcmp(__name, "address") == 0)
+    size_t length = count >= 0 ? count : __builtin_strlen(word);
+    if (length == 0)
+      return;
+
+    // Consider first '\n' at begining cause it impacts column.
+    if (word[0] == '\n')
       {
-	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;
+	fprintf(stderr, "\n");
+	ctx._M_column = 1;
+	++word;
+	--length;
 
-    return true;
-  }
+	if (length == 0)
+	  return;
+      }
 
-  void
-  print_description(
-	const __gnu_debug::_Error_formatter* __formatter,
-	const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
-  {
-    if (__variant._M_name)
+    size_t visual_length
+      = isspace(word[length - 1]) ? length - 1 : length;
+    if (visual_length == 0
+	|| !ctx._M_wordwrap
+	|| (ctx._M_column + visual_length < ctx._M_max_length)
+	|| (visual_length >= ctx._M_max_length && ctx._M_column == 1))
       {
-	const int __bufsize = 64;
-	char __buf[__bufsize];
-	__formatter->_M_format_word(__buf, __bufsize, "\"%s\"",
-				    __variant._M_name);
-	__formatter->_M_print_word(__buf);
-      }
+	// If this isn't the first line, indent
+	if (ctx._M_column == 1 && !ctx._M_first_line)
+	  {
+	    char spacing[ctx._M_indent + 1];
+	    for (int i = 0; i < ctx._M_indent; ++i)
+	      spacing[i] = ' ';
+	    spacing[ctx._M_indent] = '\0';
+	    fprintf(stderr, "%s", spacing);
+	    ctx._M_column += ctx._M_indent;
+	  }
 
-    __formatter->_M_print_word(" {\n");
+	int written = fprintf(stderr, "%s", word);
 
-    if (__variant._M_type)
+	if (word[length - 1] == '\n')
+	  {
+	    ctx._M_first_line = false;
+	    ctx._M_column = 1;
+	  }
+	else
+	  ctx._M_column += written;
+      }
+    else
       {
-	__formatter->_M_print_word("  type = ");
-	print_type(__formatter, __variant._M_type, "<unknown type>");
-	__formatter->_M_print_word(";\n");
+	print_word(ctx, "\n", 1);
+	print_word(ctx, word, count);
       }
   }
 
-
   void
-  print_description(
-	const __gnu_debug::_Error_formatter* __formatter,
-	const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  print_type(PrintContext& ctx,
+	     const type_info* info,
+	     const char* unknown_name)
   {
-    const int __bufsize = 64;
-    char __buf[__bufsize];
+    if (!info)
+      print_word(ctx, unknown_name);
+    else
+      {
+	int status;
+	char* demangled_name =
+	  __cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status);
+	print_word(ctx, status == 0 ? demangled_name : info->name());
+	free(demangled_name);
+      }
+  }
 
-    if (__variant._M_name)
+  bool
+  print_field(PrintContext& ctx,
+	      const char* name, const _Parameter::_Type& type)
+  {
+    if (__builtin_strcmp(name, "name") == 0)
       {
-	__formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
-				    __variant._M_name);
-	__formatter->_M_print_word(__buf);
+	assert(type._M_name);
+	print_word(ctx, type._M_name);
       }
+    else if (__builtin_strcmp(name, "type") == 0)
+      print_type(ctx, type._M_type, "<unknown type>");
+    else
+      return false;
 
-    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
-				__variant._M_address);
-    __formatter->_M_print_word(__buf);
+    return true;
+  }
 
-    if (__variant._M_type)
+  bool
+  print_field(PrintContext& ctx,
+	      const char* name, const _Parameter::_Instance& inst)
+  {
+    const _Parameter::_Type& type = inst;
+    if (print_field(ctx, name, type))
+      { }
+    else if (__builtin_strcmp(name, "address") == 0)
       {
-	__formatter->_M_print_word("  type = ");
-	print_type(__formatter, __variant._M_type, "<unknown type>");
+	char buf[64];
+	int ret = __builtin_sprintf(buf, "%p", inst._M_address);
+	print_word(ctx, buf, ret);
       }
+    else
+      return false;
+
+    return true;
   }
-}
 
-namespace __gnu_debug
-{
   void
-  _Error_formatter::_Parameter::
-  _M_print_field(const _Error_formatter* __formatter, const char* __name) const
+  print_field(PrintContext& ctx, const _Parameter& param, const char* name)
   {
-    assert(this->_M_kind != _Parameter::__unused_param);
-    const int __bufsize = 64;
-    char __buf[__bufsize];
+    assert(param._M_kind != _Parameter::__unused_param);
+    const int bufsize = 64;
+    char buf[bufsize];
 
-    switch (_M_kind)
+    const auto& variant = param._M_variant;
+    switch (param._M_kind)
     {
-    case __iterator:
-      if (print_field(__formatter, __name, _M_variant._M_iterator))
-	{ }
-      else if (strcmp(__name, "constness") == 0)
-	{
-	  static const char* __constness_names[__last_constness] =
-	    {
-	      "<unknown>",
-	      "constant",
-	      "mutable"
-	    };
-	  __formatter->_M_print_word(__constness_names[_M_variant.
-						       _M_iterator.
-						       _M_constness]);
-	}
-      else if (strcmp(__name, "state") == 0)
-	{
-	  static const char* __state_names[__last_state] =
-	    {
-	      "<unknown>",
-	      "singular",
-	      "dereferenceable (start-of-sequence)",
-	      "dereferenceable",
-	      "past-the-end",
-	      "before-begin"
-	    };
-	  __formatter->_M_print_word(__state_names[_M_variant.
-						   _M_iterator._M_state]);
-	}
-      else if (strcmp(__name, "sequence") == 0)
-	{
-	  assert(_M_variant._M_iterator._M_sequence);
-	  __formatter->_M_format_word(__buf, __bufsize, "%p",
-				      _M_variant._M_iterator._M_sequence);
-	  __formatter->_M_print_word(__buf);
-	}
-      else if (strcmp(__name, "seq_type") == 0)
-	print_type(__formatter, _M_variant._M_iterator._M_seq_type,
-		   "<unknown seq_type>");
-      else
-	assert(false);
+    case _Parameter::__iterator:
+      {
+	const auto& iterator = variant._M_iterator;
+	if (print_field(ctx, name, iterator))
+	  { }
+	else if (__builtin_strcmp(name, "constness") == 0)
+	  {
+	    static const char*
+	      constness_names[_Error_formatter::__last_constness] =
+	      {
+		"<unknown>",
+		"constant",
+		"mutable"
+	      };
+	    print_word(ctx, constness_names[iterator._M_constness]);
+	  }
+	else if (__builtin_strcmp(name, "state") == 0)
+	  {
+	    static const char*
+	      state_names[_Error_formatter::__last_state] =
+	      {
+		"<unknown>",
+		"singular",
+		"dereferenceable (start-of-sequence)",
+		"dereferenceable",
+		"past-the-end",
+		"before-begin"
+	      };
+	    print_word(ctx, state_names[iterator._M_state]);
+	  }
+	else if (__builtin_strcmp(name, "sequence") == 0)
+	  {
+	    assert(iterator._M_sequence);
+	    int written = __builtin_sprintf(buf, "%p", iterator._M_sequence);
+	    print_word(ctx, buf, written);
+	  }
+	else if (__builtin_strcmp(name, "seq_type") == 0)
+	  print_type(ctx, iterator._M_seq_type, "<unknown seq_type>");
+	else
+	  assert(false);
+      }
       break;
-    case __sequence:
-      if (!print_field(__formatter, __name, _M_variant._M_sequence))
+
+    case _Parameter::__sequence:
+      if (!print_field(ctx, name, variant._M_sequence))
 	assert(false);
       break;
-    case __integer:
-      if (strcmp(__name, "name") == 0)
+
+    case _Parameter::__integer:
+      if (__builtin_strcmp(name, "name") == 0)
 	{
-	  assert(_M_variant._M_integer._M_name);
-	  __formatter->_M_print_word(_M_variant._M_integer._M_name);
+	  assert(variant._M_integer._M_name);
+	  print_word(ctx, variant._M_integer._M_name);
 	}
       else
 	assert(false);
       break;
-    case __string:
-      if (strcmp(__name, "name") == 0)
+
+    case _Parameter::__string:
+      if (__builtin_strcmp(name, "name") == 0)
 	{
-	  assert(_M_variant._M_string._M_name);
-	  __formatter->_M_print_word(_M_variant._M_string._M_name);
+	  assert(variant._M_string._M_name);
+	  print_word(ctx, variant._M_string._M_name);
 	}
       else
 	assert(false);
       break;
-    case __instance:
-      if (!print_field(__formatter, __name, _M_variant._M_instance))
+
+    case _Parameter::__instance:
+      if (!print_field(ctx, name, variant._M_instance))
 	assert(false);
       break;
-    case __iterator_value_type:
-      if (!print_field(__formatter, __name, _M_variant._M_iterator_value_type))
+
+    case _Parameter::__iterator_value_type:
+      if (!print_field(ctx, name, variant._M_iterator_value_type))
 	assert(false);
       break;
+
     default:
       assert(false);
       break;
@@ -729,322 +764,298 @@ namespace __gnu_debug
   }
 
   void
-  _Error_formatter::_Parameter::
-  _M_print_description(const _Error_formatter* __formatter) const
+  print_description(PrintContext& ctx, const _Parameter::_Type& type)
   {
-    const int __bufsize = 128;
-    char __buf[__bufsize];
-
-    switch (_M_kind)
+    if (type._M_name)
       {
-      case __iterator:
-	__formatter->_M_print_word("iterator ");
-	print_description(__formatter, _M_variant._M_iterator);
-
-	if (_M_variant._M_iterator._M_type)
-	  {
-	    if (_M_variant._M_iterator._M_constness != __unknown_constness)
-	      {
-		__formatter->_M_print_word(" (");
-		_M_print_field(__formatter, "constness");
-		__formatter->_M_print_word(" iterator)");
-	      }
-	    __formatter->_M_print_word(";\n");
-	  }
-
-	if (_M_variant._M_iterator._M_state != __unknown_state)
-	  {
-	    __formatter->_M_print_word("  state = ");
-	    _M_print_field(__formatter, "state");
-	    __formatter->_M_print_word(";\n");
-	  }
-
-	if (_M_variant._M_iterator._M_sequence)
-	  {
-	    __formatter->_M_print_word("  references sequence ");
-	    if (_M_variant._M_iterator._M_seq_type)
-	      {
-		__formatter->_M_print_word("with type `");
-		_M_print_field(__formatter, "seq_type");
-		__formatter->_M_print_word("' ");
-	      }
+	const int bufsize = 64;
+	char buf[bufsize];
+	int written
+	  = format_word(buf, bufsize, "\"%s\"", type._M_name);
+	print_word(ctx, buf, written);
+      }
 
-	    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n",
-					_M_variant._M_iterator._M_sequence);
-	    __formatter->_M_print_word(__buf);
-	  }
+    print_word(ctx, " {\n");
 
-	__formatter->_M_print_word("}\n");
-	break;
-      case __sequence:
-	__formatter->_M_print_word("sequence ");
-	print_description(__formatter, _M_variant._M_sequence);
+    if (type._M_type)
+      {
+	print_word(ctx, "  type = ");
+	print_type(ctx, type._M_type, "<unknown type>");
+	print_word(ctx, ";\n");
+      }
+  }
 
-	if (_M_variant._M_sequence._M_type)
-	  __formatter->_M_print_word(";\n");
+  void
+  print_description(PrintContext& ctx, const _Parameter::_Instance& inst)
+  {
+    const int bufsize = 64;
+    char buf[bufsize];
 
-	__formatter->_M_print_word("}\n");
-	break;
-      case __instance:
-	__formatter->_M_print_word("instance ");
-	print_description(__formatter, _M_variant._M_instance);
+    if (inst._M_name)
+      {
+	int written
+	  = format_word(buf, bufsize, "\"%s\" ", inst._M_name);
+	print_word(ctx, buf, written);
+      }
 
-	if (_M_variant._M_instance._M_type)
-	  __formatter->_M_print_word(";\n");
+    int written
+      = __builtin_sprintf(buf, "@ 0x%p {\n", inst._M_address);
+    print_word(ctx, buf, written);
 
-	__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);
-	__formatter->_M_print_word("}\n");
-	break;
-      default:
-	break;
+    if (inst._M_type)
+      {
+	print_word(ctx, "  type = ");
+	print_type(ctx, inst._M_type, "<unknown type>");
       }
   }
 
-  const _Error_formatter&
-  _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
-  { return this->_M_message(_S_debug_messages[__id]); }
-
   void
-  _Error_formatter::_M_error() const
+  print_description(PrintContext& ctx, const _Parameter& param)
   {
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+    const int bufsize = 128;
+    char buf[bufsize];
 
-    // Emit file & line number information
-    _M_column = 1;
-    _M_wordwrap = false;
-    if (_M_file)
+    const auto& variant = param._M_variant;
+    switch (param._M_kind)
       {
-	_M_format_word(__buf, __bufsize, "%s:", _M_file);
-	_M_print_word(__buf);
-	_M_column += strlen(__buf);
-      }
+      case _Parameter::__iterator:
+	{
+	  const auto& ite = variant._M_iterator;
 
-    if (_M_line > 0)
-      {
-	_M_format_word(__buf, __bufsize, "%u:", _M_line);
-	_M_print_word(__buf);
-	_M_column += strlen(__buf);
-      }
+	  print_word(ctx, "iterator ");
+	  print_description(ctx, ite);
 
-    if (_M_max_length)
-      _M_wordwrap = true;
-    _M_print_word("error: ");
+	  if (ite._M_type)
+	    {
+	      if (ite._M_constness != _Error_formatter::__unknown_constness)
+		{
+		  print_word(ctx, " (");
+		  print_field(ctx, param, "constness");
+		  print_word(ctx, " iterator)");
+		}
 
-    // Print the error message
-    assert(_M_text);
-    _M_print_string(_M_text);
-    _M_print_word(".\n");
+	      print_word(ctx, ";\n");
+	    }
 
-    // Emit descriptions of the objects involved in the operation
-    _M_wordwrap = false;
-    bool __has_noninteger_parameters = false;
-    for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
-      {
-	switch (_M_parameters[__i]._M_kind)
-	  {
-	  case _Parameter::__iterator:
-	  case _Parameter::__sequence:
-	  case _Parameter::__instance:
-	  case _Parameter::__iterator_value_type:
-	    if (!__has_noninteger_parameters)
-	      {
-		_M_first_line = true;
-		_M_print_word("\nObjects involved in the operation:\n");
-		__has_noninteger_parameters = true;
-	      }
-	    _M_parameters[__i]._M_print_description(this);
-	    break;
-	  default:
-	    break;
-	  }
-      }
+	  if (ite._M_state != _Error_formatter::__unknown_state)
+	    {
+	      print_word(ctx, "  state = ");
+	      print_field(ctx, param, "state");
+	      print_word(ctx, ";\n");
+	    }
 
-    abort();
-  }
+	  if (ite._M_sequence)
+	    {
+	      print_word(ctx, "  references sequence ");
+	      if (ite._M_seq_type)
+		{
+		  print_word(ctx, "with type '");
+		  print_field(ctx, param, "seq_type");
+		  print_word(ctx, "' ");
+		}
+
+	      int written
+		= __builtin_sprintf(buf, "@ 0x%p\n", ite._M_sequence);
+	      print_word(ctx, buf, written);
+	    }
+
+	  print_word(ctx, "}\n", 2);
+	}
+	break;
 
-  template<typename _Tp>
-    void
-    _Error_formatter::_M_format_word(char* __buf,
-				     int __n __attribute__ ((__unused__)),
-				     const char* __fmt, _Tp __s) const throw ()
-    {
-#ifdef _GLIBCXX_USE_C99
-      std::snprintf(__buf, __n, __fmt, __s);
-#else
-      std::sprintf(__buf, __fmt, __s);
-#endif
-    }
+      case _Parameter::__sequence:
+	print_word(ctx, "sequence ");
+	print_description(ctx, variant._M_sequence);
 
-  void
-  _Error_formatter::_M_print_word(const char* __word) const
-  {
-    if (!_M_wordwrap)
-      {
-	fprintf(stderr, "%s", __word);
-	return;
-      }
+	if (variant._M_sequence._M_type)
+	  print_word(ctx, ";\n", 2);
 
-    size_t __length = strlen(__word);
-    if (__length == 0)
-      return;
+	print_word(ctx, "}\n", 2);
+	break;
 
-    size_t __visual_length
-      = __word[__length - 1] == '\n' ? __length - 1 : __length;
-    if (__visual_length == 0
-	|| (_M_column + __visual_length < _M_max_length)
-	|| (__visual_length >= _M_max_length && _M_column == 1))
-      {
-	// If this isn't the first line, indent
-	if (_M_column == 1 && !_M_first_line)
-	  {
-	    char __spacing[_M_indent + 1];
-	    for (int i = 0; i < _M_indent; ++i)
-	      __spacing[i] = ' ';
-	    __spacing[_M_indent] = '\0';
-	    fprintf(stderr, "%s", __spacing);
-	    _M_column += _M_indent;
-	  }
+      case _Parameter::__instance:
+	print_word(ctx, "instance ");
+	print_description(ctx, variant._M_instance);
 
-	fprintf(stderr, "%s", __word);
+	if (variant._M_instance._M_type)
+	  print_word(ctx, ";\n", 2);
 
-	if (__word[__length - 1] == '\n')
-	  {
-	    _M_first_line = false;
-	    _M_column = 1;
-	  }
-	else
-	  _M_column += __length;
-      }
-    else
-      {
-	_M_print_word("\n");
-	_M_print_word(__word);
+	print_word(ctx, "}\n", 2);
+	break;
+
+      case _Parameter::__iterator_value_type:
+	print_word(ctx, "iterator::value_type ");
+	print_description(ctx, variant._M_iterator_value_type);
+	print_word(ctx, "}\n", 2);
+	break;
+
+      default:
+	break;
       }
   }
 
   void
-  _Error_formatter::
-  _M_print_string(const char* __string) const
+  print_string(PrintContext& ctx, const char* string,
+	       const _Parameter* parameters, std::size_t num_parameters)
   {
-    const char* __start = __string;
-    const char* __finish = __start;
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+    const char* start = string;
+    const int bufsize = 128;
+    char buf[bufsize];
+    int bufindex = 0;
 
-    while (*__start)
+    while (*start)
       {
-	if (*__start != '%')
+	if (isspace(*start))
 	  {
-	    // [__start, __finish) denotes the next word
-	    __finish = __start;
-	    while (isalnum(*__finish))
-	      ++__finish;
-	    if (__start == __finish)
-	      ++__finish;
-	    if (isspace(*__finish))
-	      ++__finish;
-
-	    const ptrdiff_t __len = __finish - __start;
-	    assert(__len < __bufsize);
-	    memcpy(__buf, __start, __len);
-	    __buf[__len] = '\0';
-	    _M_print_word(__buf);
-	    __start = __finish;
-
-	    // Skip extra whitespace
-	    while (*__start == ' ')
-	      ++__start;
+	    buf[bufindex++] = *start++;
+	    buf[bufindex] = '\0';
+	    print_word(ctx, buf, bufindex);
+	    bufindex = 0;
+	    continue;
+	  }
 
+	if (*start != '%')
+	  {
+	    // Normal char.
+	    buf[bufindex++] = *start++;
 	    continue;
 	  }
 
-	++__start;
-	assert(*__start);
-	if (*__start == '%')
+	if (*++start == '%')
 	  {
-	    _M_print_word("%");
-	    ++__start;
+	    // Escaped '%'
+	    buf[bufindex++] = *start++;
 	    continue;
 	  }
 
+	// We are on a parameter property reference, we need to flush buffer
+	// first.
+	if (bufindex != 0)
+	  {
+	    buf[bufindex] = '\0';
+	    print_word(ctx, buf, bufindex);
+	    bufindex = 0;
+	  }
+
 	// Get the parameter number
-	assert(*__start >= '1' && *__start <= '9');
-	size_t __param_index = *__start - '0' - 1;
-	assert(__param_index < _M_num_parameters);
-	const auto& __param = _M_parameters[__param_index];
+	assert(*start >= '1' && *start <= '9');
+	size_t param_index = *start - '0' - 1;
+	assert(param_index < num_parameters);
+	const auto& param = parameters[param_index];
 
 	// '.' separates the parameter number from the field
 	// name, if there is one.
-	++__start;
-	if (*__start != '.')
+	++start;
+	if (*start != '.')
 	  {
-	    assert(*__start == ';');
-	    ++__start;
-	    __buf[0] = '\0';
-	    if (__param._M_kind == _Parameter::__integer)
+	    assert(*start == ';');
+	    ++start;
+	    if (param._M_kind == _Parameter::__integer)
 	      {
-		_M_format_word(__buf, __bufsize, "%ld",
-			       __param._M_variant._M_integer._M_value);
-		_M_print_word(__buf);
+		int written
+		  = __builtin_sprintf(buf, "%ld",
+				      param._M_variant._M_integer._M_value);
+		print_word(ctx, buf, written);
 	      }
-	    else if (__param._M_kind == _Parameter::__string)
-	      _M_print_string(__param._M_variant._M_string._M_value);
+	    else if (param._M_kind == _Parameter::__string)
+	      print_string(ctx, param._M_variant._M_string._M_value,
+			   parameters, num_parameters);
 	    continue;
 	  }
 
 	// Extract the field name we want
-	enum { __max_field_len = 16 };
-	char __field[__max_field_len];
-	int __field_idx = 0;
-	++__start;
-	while (*__start != ';')
+	const int max_field_len = 16;
+	char field[max_field_len];
+	int field_idx = 0;
+	++start;
+	while (*start != ';')
 	  {
-	    assert(*__start);
-	    assert(__field_idx < __max_field_len-1);
-	    __field[__field_idx++] = *__start++;
+	    assert(*start);
+	    assert(field_idx < max_field_len - 1);
+	    field[field_idx++] = *start++;
 	  }
-	++__start;
-	__field[__field_idx] = 0;
+	++start;
+	field[field_idx] = '\0';
 
-	__param._M_print_field(this, __field);
+	print_field(ctx, param, field);
+      }
+
+    // Might need to flush.
+    if (bufindex)
+      {
+	buf[bufindex] = '\0';
+	print_word(ctx, buf, bufindex);
       }
   }
+}
+
+namespace __gnu_debug
+{
+  _Error_formatter&
+  _Error_formatter::_M_message(_Debug_msg_id __id) throw ()
+  { return this->_M_message(_S_debug_messages[__id]); }
 
   void
-  _Error_formatter::_M_get_max_length() const throw ()
+  _Error_formatter::_M_error() const
   {
-    const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
-    if (__nptr)
+    const int bufsize = 128;
+    char buf[bufsize];
+
+    // Emit file & line number information
+    bool go_to_next_line = false;
+    PrintContext ctx;
+    if (_M_file)
       {
-	char* __endptr;
-	const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
-	if (*__nptr != '\0' && *__endptr == '\0')
-	  _M_max_length = __ret;
+	int written = format_word(buf, bufsize, "%s:", _M_file);
+	print_word(ctx, buf, written);
+	go_to_next_line = true;
       }
-  }
 
-  // Instantiations.
-  template
-    void
-    _Error_formatter::_M_format_word(char*, int, const char*,
-				     const void*) const;
-
-  template
-    void
-    _Error_formatter::_M_format_word(char*, int, const char*, long) const;
-
-  template
-    void
-    _Error_formatter::_M_format_word(char*, int, const char*,
-				     std::size_t) const;
-
-  template
-    void
-    _Error_formatter::_M_format_word(char*, int, const char*,
-				     const char*) const;
+    if (_M_line > 0)
+      {
+	int written = __builtin_sprintf(buf, "%u:", _M_line);
+	print_word(ctx, buf, written);
+	go_to_next_line = true;
+      }
+
+    if (go_to_next_line)
+      print_word(ctx, "\n", 1);
+
+    if (ctx._M_max_length)
+      ctx._M_wordwrap = true;
+
+    print_word(ctx, "Error: ");
+
+    // Print the error message
+    assert(_M_text);
+    print_string(ctx, _M_text, _M_parameters, _M_num_parameters);
+    print_word(ctx, ".\n", 2);
+
+    // Emit descriptions of the objects involved in the operation
+    ctx._M_first_line = true;
+    ctx._M_wordwrap = false;
+    bool has_header = false;
+    for (unsigned int i = 0; i < _M_num_parameters; ++i)
+      {
+	switch (_M_parameters[i]._M_kind)
+	  {
+	  case _Parameter::__iterator:
+	  case _Parameter::__sequence:
+	  case _Parameter::__instance:
+	  case _Parameter::__iterator_value_type:
+	    if (!has_header)
+	      {
+		print_word(ctx, "\nObjects involved in the operation:\n");
+		has_header = true;
+	      }
+	    print_description(ctx, _M_parameters[i]);
+	    break;
+
+	  default:
+	    break;
+	  }
+      }
+
+    abort();
+  }
 } // namespace __gnu_debug

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-05 21:02 debug mode symbols cleanup François Dumont
@ 2015-09-07 11:04 ` Jonathan Wakely
  2015-09-08 21:02   ` François Dumont
  2015-09-18 11:06 ` Ulrich Weigand
  1 sibling, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2015-09-07 11:04 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 05/09/15 22:53 +0200, François Dumont wrote:
>    I remember Paolo saying once that we were not guarantiing any abi
>compatibility for debug mode. I haven't found any section for
>unversioned symbols in gnu.ver so I simply uncomment the global export.

There is no section, because all exported symbols are versioned.

It's OK if objects compiled with Debug Mode using one version of GCC
don't link to objects compiled with Debug Mode using a different
version of GCC, but you can't change the exported symbols in the DSO.


Your changelog doesn't include the changes to config/abi/pre/gnu.ver,
but those changes are not OK anyway, they fail the abi-check:

FAIL: libstdc++-abi/abi_check

                === libstdc++ Summary ===

# of unexpected failures        1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-07 11:04 ` Jonathan Wakely
@ 2015-09-08 21:02   ` François Dumont
  2015-09-14 18:27     ` François Dumont
  0 siblings, 1 reply; 9+ messages in thread
From: François Dumont @ 2015-09-08 21:02 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1248 bytes --]

On 07/09/2015 13:03, Jonathan Wakely wrote:
> On 05/09/15 22:53 +0200, François Dumont wrote:
>>    I remember Paolo saying once that we were not guarantiing any abi
>> compatibility for debug mode. I haven't found any section for
>> unversioned symbols in gnu.ver so I simply uncomment the global export.
>
> There is no section, because all exported symbols are versioned.
>
> It's OK if objects compiled with Debug Mode using one version of GCC
> don't link to objects compiled with Debug Mode using a different
> version of GCC, but you can't change the exported symbols in the DSO.
>
>
> Your changelog doesn't include the changes to config/abi/pre/gnu.ver,
> but those changes are not OK anyway, they fail the abi-check:
>
> FAIL: libstdc++-abi/abi_check
>
>                === libstdc++ Summary ===
>
> # of unexpected failures        1
>
>
Sorry, I though policy regarding debug mode symbols was even more relax.
It is not so here is another patch that doesn"t break abi checks.

I eventually made all methods that should not be used deprecated, they
were normally not used explicitely anyway. Their implementation is now
empty. I just needed to add a symbol for the not const _M_message method
which is the correct signature.

François


[-- Attachment #2: debug.patch --]
[-- Type: text/x-patch, Size: 32973 bytes --]

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 8f9f99a..ac9a66b 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1879,6 +1879,8 @@ GLIBCXX_3.4.22 {
 
     _ZNSt6vectorIPSt12Catalog_info*;
 
+    _ZN11__gnu_debug16_Error_formatter10_M_message*;
+
 } GLIBCXX_3.4.21;
 
 # Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h
index f0ac694..1826e94 100644
--- a/libstdc++-v3/include/debug/formatter.h
+++ b/libstdc++-v3/include/debug/formatter.h
@@ -133,6 +133,13 @@ namespace __gnu_debug
 
   class _Error_formatter
   {
+    // Tags denoting the type of parameter for construction
+    struct _Is_iterator { };
+    struct _Is_iterator_value_type { };
+    struct _Is_sequence { };
+    struct _Is_instance { };
+
+  public:
     /// Whether an iterator is constant, mutable, or unknown
     enum _Constness
     {
@@ -154,13 +161,6 @@ namespace __gnu_debug
       __last_state
     };
 
-    // 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
     {
@@ -376,15 +376,16 @@ namespace __gnu_debug
 
       void
       _M_print_field(const _Error_formatter* __formatter,
-		     const char* __name) const;
+		     const char* __name) const _GLIBCXX_DEPRECATED;
 
       void
-      _M_print_description(const _Error_formatter* __formatter) const;
+      _M_print_description(const _Error_formatter* __formatter)
+	const _GLIBCXX_DEPRECATED;
     };
 
     template<typename _Iterator>
-      const _Error_formatter&
-      _M_iterator(const _Iterator& __it, const char* __name = 0)  const
+      _Error_formatter&
+      _M_iterator(const _Iterator& __it, const char* __name = 0)
       {
 	if (_M_num_parameters < std::size_t(__max_parameters))
 	  _M_parameters[_M_num_parameters++] = _Parameter(__it, __name,
@@ -393,98 +394,99 @@ namespace __gnu_debug
       }
 
     template<typename _Iterator>
-      const _Error_formatter&
+      _Error_formatter&
       _M_iterator_value_type(const _Iterator& __it,
-			     const char* __name = 0)  const
+			     const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __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
+    _Error_formatter&
+    _M_integer(long __value, const char* __name = 0)
     {
-      if (_M_num_parameters < std::size_t(__max_parameters))
+      if (_M_num_parameters < __max_parameters)
 	_M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
       return *this;
     }
 
-    const _Error_formatter&
-    _M_string(const char* __value, const char* __name = 0) const
+    _Error_formatter&
+    _M_string(const char* __value, const char* __name = 0)
     {
-      if (_M_num_parameters < std::size_t(__max_parameters))
+      if (_M_num_parameters < __max_parameters)
 	_M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
       return *this;
     }
 
     template<typename _Sequence>
-      const _Error_formatter&
-      _M_sequence(const _Sequence& __seq, const char* __name = 0) const
+      _Error_formatter&
+      _M_sequence(const _Sequence& __seq, const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __max_parameters)
 	  _M_parameters[_M_num_parameters++] = _Parameter(__seq, __name,
 							  _Is_sequence());
 	return *this;
       }
 
     template<typename _Type>
-      const _Error_formatter&
-      _M_instance(const _Type& __inst, const char* __name = 0) const
+      _Error_formatter&
+      _M_instance(const _Type& __inst, const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __max_parameters)
 	  _M_parameters[_M_num_parameters++] = _Parameter(__inst, __name,
 							  _Is_instance());
 	return *this;
       }
 
-    const _Error_formatter&
-    _M_message(const char* __text) const
+    _Error_formatter&
+    _M_message(const char* __text)
     { _M_text = __text; return *this; }
 
+    _Error_formatter&
+    _M_message(_Debug_msg_id __id) throw ();
+
     const _Error_formatter&
-    _M_message(_Debug_msg_id __id) const throw ();
+    _M_message(_Debug_msg_id __id) const throw () _GLIBCXX_DEPRECATED;
 
     _GLIBCXX_NORETURN void
     _M_error() const;
 
     template<typename _Tp>
       void
-      _M_format_word(char*, int, const char*, _Tp) const throw ();
+      _M_format_word(char*, int, const char*, _Tp)
+      const throw () _GLIBCXX_DEPRECATED;
 
     void
-    _M_print_word(const char* __word) const;
+    _M_print_word(const char* __word) const _GLIBCXX_DEPRECATED;
 
     void
-    _M_print_string(const char* __string) const;
+    _M_print_string(const char* __string) const _GLIBCXX_DEPRECATED;
 
   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(); }
+    _Error_formatter(const char* __file, unsigned int __line)
+    : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0)
+    { }
 
     void
-    _M_get_max_length() const throw ();
+    _M_get_max_length() const throw () _GLIBCXX_DEPRECATED;
 
     enum { __max_parameters = 9 };
 
     const char*		_M_file;
-    std::size_t		_M_line;
-    mutable _Parameter	_M_parameters[__max_parameters];
-    mutable std::size_t	_M_num_parameters;
-    mutable const char*	_M_text;
-    mutable std::size_t	_M_max_length;
-    enum { _M_indent = 4 } ;
-    mutable std::size_t	_M_column;
-    mutable bool	_M_first_line;
-    mutable bool	_M_wordwrap;
+    unsigned int	_M_line;
+    _Parameter		_M_parameters[__max_parameters];
+    unsigned int	_M_num_parameters;
+    const char*		_M_text;
 
   public:
-    static _Error_formatter
-    _M_at(const char* __file, std::size_t __line)
-    { return _Error_formatter(__file, __line); }
+    static _Error_formatter&
+    _M_at(const char* __file, unsigned int __line)
+    {
+      static _Error_formatter __formatter(__file, __line);
+      return __formatter;
+    }
   };
 } // namespace __gnu_debug
 
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index d3f8cae..0a2f3d4 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -22,18 +22,19 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // <http://www.gnu.org/licenses/>.
 
-#include <debug/debug.h>
+#include <bits/move.h>
+#include <bits/stl_iterator_base_types.h>
+
+#include <debug/formatter.h>
 #include <debug/safe_base.h>
 #include <debug/safe_unordered_base.h>
 #include <debug/safe_iterator.h>
 #include <debug/safe_local_iterator.h>
-#include <algorithm>
+
 #include <cassert>
-#include <cstring>
-#include <cctype>
-#include <cstdio>
-#include <cstdlib>
-#include <functional>
+
+#include <algorithm> // for std::min
+#include <functional> // for _Hash_impl
 
 #include <cxxabi.h> // for __cxa_demangle
 
@@ -526,202 +527,236 @@ namespace __gnu_debug
 
 namespace
 {
+  using _Error_formatter = __gnu_debug::_Error_formatter;
+  using _Parameter = __gnu_debug::_Error_formatter::_Parameter;
+
+  template<typename _Tp>
+    int
+    format_word(char* buf, int n, const char* fmt, _Tp s)
+    { return std::min(__builtin_snprintf(buf, n, fmt, s), n - 1); }
+
   void
-  print_type(const __gnu_debug::_Error_formatter* __formatter,
-	     const type_info* __info,
-	     const char* __unknown_name)
+  get_max_length(std::size_t& max_length)
   {
-    if (!__info)
-      __formatter->_M_print_word(__unknown_name);
-    else
+    const char* nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
+    if (nptr)
       {
-	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);
+	char* endptr;
+	const unsigned long ret = std::strtoul(nptr, &endptr, 0);
+	if (*nptr != '\0' && *endptr == '\0')
+	  max_length = ret;
       }
   }
 
-  bool
-  print_field(
-    const __gnu_debug::_Error_formatter* __formatter,
-    const char* __name,
-    const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
+  struct PrintContext
   {
-    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;
-  }
+    PrintContext()
+      : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false)
+    { get_max_length(_M_max_length); }
+
+    std::size_t	_M_max_length;
+    enum { _M_indent = 4 } ;
+    std::size_t	_M_column;
+    bool	_M_first_line;
+    bool	_M_wordwrap;
+  };
 
-  bool
-  print_field(
-    const __gnu_debug::_Error_formatter* __formatter,
-    const char* __name,
-    const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  void
+  print_word(PrintContext& ctx, const char* word,
+	     std::ptrdiff_t count = -1)
   {
-    const __gnu_debug::_Error_formatter::_Parameter::_Type& __type = __variant;
-    if (print_field(__formatter, __name, __type))
-      { }
-    else if (strcmp(__name, "address") == 0)
+    size_t length = count >= 0 ? count : __builtin_strlen(word);
+    if (length == 0)
+      return;
+
+    // Consider first '\n' at begining cause it impacts column.
+    if (word[0] == '\n')
       {
-	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;
+	fprintf(stderr, "\n");
+	ctx._M_column = 1;
+	++word;
+	--length;
 
-    return true;
-  }
+	if (length == 0)
+	  return;
+      }
 
-  void
-  print_description(
-	const __gnu_debug::_Error_formatter* __formatter,
-	const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
-  {
-    if (__variant._M_name)
+    size_t visual_length
+      = isspace(word[length - 1]) ? length - 1 : length;
+    if (visual_length == 0
+	|| !ctx._M_wordwrap
+	|| (ctx._M_column + visual_length < ctx._M_max_length)
+	|| (visual_length >= ctx._M_max_length && ctx._M_column == 1))
       {
-	const int __bufsize = 64;
-	char __buf[__bufsize];
-	__formatter->_M_format_word(__buf, __bufsize, "\"%s\"",
-				    __variant._M_name);
-	__formatter->_M_print_word(__buf);
-      }
+	// If this isn't the first line, indent
+	if (ctx._M_column == 1 && !ctx._M_first_line)
+	  {
+	    char spacing[ctx._M_indent + 1];
+	    for (int i = 0; i < ctx._M_indent; ++i)
+	      spacing[i] = ' ';
+	    spacing[ctx._M_indent] = '\0';
+	    fprintf(stderr, "%s", spacing);
+	    ctx._M_column += ctx._M_indent;
+	  }
 
-    __formatter->_M_print_word(" {\n");
+	int written = fprintf(stderr, "%s", word);
 
-    if (__variant._M_type)
+	if (word[length - 1] == '\n')
+	  {
+	    ctx._M_first_line = false;
+	    ctx._M_column = 1;
+	  }
+	else
+	  ctx._M_column += written;
+      }
+    else
       {
-	__formatter->_M_print_word("  type = ");
-	print_type(__formatter, __variant._M_type, "<unknown type>");
-	__formatter->_M_print_word(";\n");
+	print_word(ctx, "\n", 1);
+	print_word(ctx, word, count);
       }
   }
 
-
   void
-  print_description(
-	const __gnu_debug::_Error_formatter* __formatter,
-	const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  print_type(PrintContext& ctx,
+	     const type_info* info,
+	     const char* unknown_name)
   {
-    const int __bufsize = 64;
-    char __buf[__bufsize];
+    if (!info)
+      print_word(ctx, unknown_name);
+    else
+      {
+	int status;
+	char* demangled_name =
+	  __cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status);
+	print_word(ctx, status == 0 ? demangled_name : info->name());
+	free(demangled_name);
+      }
+  }
 
-    if (__variant._M_name)
+  bool
+  print_field(PrintContext& ctx,
+	      const char* name, const _Parameter::_Type& type)
+  {
+    if (__builtin_strcmp(name, "name") == 0)
       {
-	__formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
-				    __variant._M_name);
-	__formatter->_M_print_word(__buf);
+	assert(type._M_name);
+	print_word(ctx, type._M_name);
       }
+    else if (__builtin_strcmp(name, "type") == 0)
+      print_type(ctx, type._M_type, "<unknown type>");
+    else
+      return false;
 
-    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
-				__variant._M_address);
-    __formatter->_M_print_word(__buf);
+    return true;
+  }
 
-    if (__variant._M_type)
+  bool
+  print_field(PrintContext& ctx,
+	      const char* name, const _Parameter::_Instance& inst)
+  {
+    const _Parameter::_Type& type = inst;
+    if (print_field(ctx, name, type))
+      { }
+    else if (__builtin_strcmp(name, "address") == 0)
       {
-	__formatter->_M_print_word("  type = ");
-	print_type(__formatter, __variant._M_type, "<unknown type>");
+	char buf[64];
+	int ret = __builtin_sprintf(buf, "%p", inst._M_address);
+	print_word(ctx, buf, ret);
       }
+    else
+      return false;
+
+    return true;
   }
-}
 
-namespace __gnu_debug
-{
   void
-  _Error_formatter::_Parameter::
-  _M_print_field(const _Error_formatter* __formatter, const char* __name) const
+  print_field(PrintContext& ctx, const _Parameter& param, const char* name)
   {
-    assert(this->_M_kind != _Parameter::__unused_param);
-    const int __bufsize = 64;
-    char __buf[__bufsize];
+    assert(param._M_kind != _Parameter::__unused_param);
+    const int bufsize = 64;
+    char buf[bufsize];
 
-    switch (_M_kind)
+    const auto& variant = param._M_variant;
+    switch (param._M_kind)
     {
-    case __iterator:
-      if (print_field(__formatter, __name, _M_variant._M_iterator))
-	{ }
-      else if (strcmp(__name, "constness") == 0)
-	{
-	  static const char* __constness_names[__last_constness] =
-	    {
-	      "<unknown>",
-	      "constant",
-	      "mutable"
-	    };
-	  __formatter->_M_print_word(__constness_names[_M_variant.
-						       _M_iterator.
-						       _M_constness]);
-	}
-      else if (strcmp(__name, "state") == 0)
-	{
-	  static const char* __state_names[__last_state] =
-	    {
-	      "<unknown>",
-	      "singular",
-	      "dereferenceable (start-of-sequence)",
-	      "dereferenceable",
-	      "past-the-end",
-	      "before-begin"
-	    };
-	  __formatter->_M_print_word(__state_names[_M_variant.
-						   _M_iterator._M_state]);
-	}
-      else if (strcmp(__name, "sequence") == 0)
-	{
-	  assert(_M_variant._M_iterator._M_sequence);
-	  __formatter->_M_format_word(__buf, __bufsize, "%p",
-				      _M_variant._M_iterator._M_sequence);
-	  __formatter->_M_print_word(__buf);
-	}
-      else if (strcmp(__name, "seq_type") == 0)
-	print_type(__formatter, _M_variant._M_iterator._M_seq_type,
-		   "<unknown seq_type>");
-      else
-	assert(false);
+    case _Parameter::__iterator:
+      {
+	const auto& iterator = variant._M_iterator;
+	if (print_field(ctx, name, iterator))
+	  { }
+	else if (__builtin_strcmp(name, "constness") == 0)
+	  {
+	    static const char*
+	      constness_names[_Error_formatter::__last_constness] =
+	      {
+		"<unknown>",
+		"constant",
+		"mutable"
+	      };
+	    print_word(ctx, constness_names[iterator._M_constness]);
+	  }
+	else if (__builtin_strcmp(name, "state") == 0)
+	  {
+	    static const char*
+	      state_names[_Error_formatter::__last_state] =
+	      {
+		"<unknown>",
+		"singular",
+		"dereferenceable (start-of-sequence)",
+		"dereferenceable",
+		"past-the-end",
+		"before-begin"
+	      };
+	    print_word(ctx, state_names[iterator._M_state]);
+	  }
+	else if (__builtin_strcmp(name, "sequence") == 0)
+	  {
+	    assert(iterator._M_sequence);
+	    int written = __builtin_sprintf(buf, "%p", iterator._M_sequence);
+	    print_word(ctx, buf, written);
+	  }
+	else if (__builtin_strcmp(name, "seq_type") == 0)
+	  print_type(ctx, iterator._M_seq_type, "<unknown seq_type>");
+	else
+	  assert(false);
+      }
       break;
-    case __sequence:
-      if (!print_field(__formatter, __name, _M_variant._M_sequence))
+
+    case _Parameter::__sequence:
+      if (!print_field(ctx, name, variant._M_sequence))
 	assert(false);
       break;
-    case __integer:
-      if (strcmp(__name, "name") == 0)
+
+    case _Parameter::__integer:
+      if (__builtin_strcmp(name, "name") == 0)
 	{
-	  assert(_M_variant._M_integer._M_name);
-	  __formatter->_M_print_word(_M_variant._M_integer._M_name);
+	  assert(variant._M_integer._M_name);
+	  print_word(ctx, variant._M_integer._M_name);
 	}
       else
 	assert(false);
       break;
-    case __string:
-      if (strcmp(__name, "name") == 0)
+
+    case _Parameter::__string:
+      if (__builtin_strcmp(name, "name") == 0)
 	{
-	  assert(_M_variant._M_string._M_name);
-	  __formatter->_M_print_word(_M_variant._M_string._M_name);
+	  assert(variant._M_string._M_name);
+	  print_word(ctx, variant._M_string._M_name);
 	}
       else
 	assert(false);
       break;
-    case __instance:
-      if (!print_field(__formatter, __name, _M_variant._M_instance))
+
+    case _Parameter::__instance:
+      if (!print_field(ctx, name, variant._M_instance))
 	assert(false);
       break;
-    case __iterator_value_type:
-      if (!print_field(__formatter, __name, _M_variant._M_iterator_value_type))
+
+    case _Parameter::__iterator_value_type:
+      if (!print_field(ctx, name, variant._M_iterator_value_type))
 	assert(false);
       break;
+
     default:
       assert(false);
       break;
@@ -729,136 +764,293 @@ namespace __gnu_debug
   }
 
   void
-  _Error_formatter::_Parameter::
-  _M_print_description(const _Error_formatter* __formatter) const
+  print_description(PrintContext& ctx, const _Parameter::_Type& type)
   {
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+    if (type._M_name)
+      {
+	const int bufsize = 64;
+	char buf[bufsize];
+	int written
+	  = format_word(buf, bufsize, "\"%s\"", type._M_name);
+	print_word(ctx, buf, written);
+      }
+
+    print_word(ctx, " {\n");
 
-    switch (_M_kind)
+    if (type._M_type)
       {
-      case __iterator:
-	__formatter->_M_print_word("iterator ");
-	print_description(__formatter, _M_variant._M_iterator);
+	print_word(ctx, "  type = ");
+	print_type(ctx, type._M_type, "<unknown type>");
+	print_word(ctx, ";\n");
+      }
+  }
 
-	if (_M_variant._M_iterator._M_type)
-	  {
-	    if (_M_variant._M_iterator._M_constness != __unknown_constness)
-	      {
-		__formatter->_M_print_word(" (");
-		_M_print_field(__formatter, "constness");
-		__formatter->_M_print_word(" iterator)");
-	      }
-	    __formatter->_M_print_word(";\n");
-	  }
+  void
+  print_description(PrintContext& ctx, const _Parameter::_Instance& inst)
+  {
+    const int bufsize = 64;
+    char buf[bufsize];
 
-	if (_M_variant._M_iterator._M_state != __unknown_state)
-	  {
-	    __formatter->_M_print_word("  state = ");
-	    _M_print_field(__formatter, "state");
-	    __formatter->_M_print_word(";\n");
-	  }
+    if (inst._M_name)
+      {
+	int written
+	  = format_word(buf, bufsize, "\"%s\" ", inst._M_name);
+	print_word(ctx, buf, written);
+      }
 
-	if (_M_variant._M_iterator._M_sequence)
-	  {
-	    __formatter->_M_print_word("  references sequence ");
-	    if (_M_variant._M_iterator._M_seq_type)
-	      {
-		__formatter->_M_print_word("with type `");
-		_M_print_field(__formatter, "seq_type");
-		__formatter->_M_print_word("' ");
-	      }
+    int written
+      = __builtin_sprintf(buf, "@ 0x%p {\n", inst._M_address);
+    print_word(ctx, buf, written);
 
-	    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n",
-					_M_variant._M_iterator._M_sequence);
-	    __formatter->_M_print_word(__buf);
-	  }
+    if (inst._M_type)
+      {
+	print_word(ctx, "  type = ");
+	print_type(ctx, inst._M_type, "<unknown type>");
+      }
+  }
+
+  void
+  print_description(PrintContext& ctx, const _Parameter& param)
+  {
+    const int bufsize = 128;
+    char buf[bufsize];
+
+    const auto& variant = param._M_variant;
+    switch (param._M_kind)
+      {
+      case _Parameter::__iterator:
+	{
+	  const auto& ite = variant._M_iterator;
+
+	  print_word(ctx, "iterator ");
+	  print_description(ctx, ite);
 
-	__formatter->_M_print_word("}\n");
+	  if (ite._M_type)
+	    {
+	      if (ite._M_constness != _Error_formatter::__unknown_constness)
+		{
+		  print_word(ctx, " (");
+		  print_field(ctx, param, "constness");
+		  print_word(ctx, " iterator)");
+		}
+
+	      print_word(ctx, ";\n");
+	    }
+
+	  if (ite._M_state != _Error_formatter::__unknown_state)
+	    {
+	      print_word(ctx, "  state = ");
+	      print_field(ctx, param, "state");
+	      print_word(ctx, ";\n");
+	    }
+
+	  if (ite._M_sequence)
+	    {
+	      print_word(ctx, "  references sequence ");
+	      if (ite._M_seq_type)
+		{
+		  print_word(ctx, "with type '");
+		  print_field(ctx, param, "seq_type");
+		  print_word(ctx, "' ");
+		}
+
+	      int written
+		= __builtin_sprintf(buf, "@ 0x%p\n", ite._M_sequence);
+	      print_word(ctx, buf, written);
+	    }
+
+	  print_word(ctx, "}\n", 2);
+	}
 	break;
-      case __sequence:
-	__formatter->_M_print_word("sequence ");
-	print_description(__formatter, _M_variant._M_sequence);
 
-	if (_M_variant._M_sequence._M_type)
-	  __formatter->_M_print_word(";\n");
+      case _Parameter::__sequence:
+	print_word(ctx, "sequence ");
+	print_description(ctx, variant._M_sequence);
+
+	if (variant._M_sequence._M_type)
+	  print_word(ctx, ";\n", 2);
 
-	__formatter->_M_print_word("}\n");
+	print_word(ctx, "}\n", 2);
 	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");
+      case _Parameter::__instance:
+	print_word(ctx, "instance ");
+	print_description(ctx, variant._M_instance);
 
-	__formatter->_M_print_word("}\n");
+	if (variant._M_instance._M_type)
+	  print_word(ctx, ";\n", 2);
+
+	print_word(ctx, "}\n", 2);
 	break;
-      case __iterator_value_type:
-	__formatter->_M_print_word("iterator::value_type ");
-	print_description(__formatter, _M_variant._M_iterator_value_type);
-	__formatter->_M_print_word("}\n");
+
+      case _Parameter::__iterator_value_type:
+	print_word(ctx, "iterator::value_type ");
+	print_description(ctx, variant._M_iterator_value_type);
+	print_word(ctx, "}\n", 2);
 	break;
+
       default:
 	break;
       }
   }
 
-  const _Error_formatter&
-  _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
+  void
+  print_string(PrintContext& ctx, const char* string,
+	       const _Parameter* parameters, std::size_t num_parameters)
+  {
+    const char* start = string;
+    const int bufsize = 128;
+    char buf[bufsize];
+    int bufindex = 0;
+
+    while (*start)
+      {
+	if (isspace(*start))
+	  {
+	    buf[bufindex++] = *start++;
+	    buf[bufindex] = '\0';
+	    print_word(ctx, buf, bufindex);
+	    bufindex = 0;
+	    continue;
+	  }
+
+	if (*start != '%')
+	  {
+	    // Normal char.
+	    buf[bufindex++] = *start++;
+	    continue;
+	  }
+
+	if (*++start == '%')
+	  {
+	    // Escaped '%'
+	    buf[bufindex++] = *start++;
+	    continue;
+	  }
+
+	// We are on a parameter property reference, we need to flush buffer
+	// first.
+	if (bufindex != 0)
+	  {
+	    buf[bufindex] = '\0';
+	    print_word(ctx, buf, bufindex);
+	    bufindex = 0;
+	  }
+
+	// Get the parameter number
+	assert(*start >= '1' && *start <= '9');
+	size_t param_index = *start - '0' - 1;
+	assert(param_index < num_parameters);
+	const auto& param = parameters[param_index];
+
+	// '.' separates the parameter number from the field
+	// name, if there is one.
+	++start;
+	if (*start != '.')
+	  {
+	    assert(*start == ';');
+	    ++start;
+	    if (param._M_kind == _Parameter::__integer)
+	      {
+		int written
+		  = __builtin_sprintf(buf, "%ld",
+				      param._M_variant._M_integer._M_value);
+		print_word(ctx, buf, written);
+	      }
+	    else if (param._M_kind == _Parameter::__string)
+	      print_string(ctx, param._M_variant._M_string._M_value,
+			   parameters, num_parameters);
+	    continue;
+	  }
+
+	// Extract the field name we want
+	const int max_field_len = 16;
+	char field[max_field_len];
+	int field_idx = 0;
+	++start;
+	while (*start != ';')
+	  {
+	    assert(*start);
+	    assert(field_idx < max_field_len - 1);
+	    field[field_idx++] = *start++;
+	  }
+	++start;
+	field[field_idx] = '\0';
+
+	print_field(ctx, param, field);
+      }
+
+    // Might need to flush.
+    if (bufindex)
+      {
+	buf[bufindex] = '\0';
+	print_word(ctx, buf, bufindex);
+      }
+  }
+}
+
+namespace __gnu_debug
+{
+  _Error_formatter&
+  _Error_formatter::_M_message(_Debug_msg_id __id) throw ()
   { return this->_M_message(_S_debug_messages[__id]); }
 
   void
   _Error_formatter::_M_error() const
   {
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+    const int bufsize = 128;
+    char buf[bufsize];
 
     // Emit file & line number information
-    _M_column = 1;
-    _M_wordwrap = false;
+    bool go_to_next_line = false;
+    PrintContext ctx;
     if (_M_file)
       {
-	_M_format_word(__buf, __bufsize, "%s:", _M_file);
-	_M_print_word(__buf);
-	_M_column += strlen(__buf);
+	int written = format_word(buf, bufsize, "%s:", _M_file);
+	print_word(ctx, buf, written);
+	go_to_next_line = true;
       }
 
     if (_M_line > 0)
       {
-	_M_format_word(__buf, __bufsize, "%u:", _M_line);
-	_M_print_word(__buf);
-	_M_column += strlen(__buf);
+	int written = __builtin_sprintf(buf, "%u:", _M_line);
+	print_word(ctx, buf, written);
+	go_to_next_line = true;
       }
 
-    if (_M_max_length)
-      _M_wordwrap = true;
-    _M_print_word("error: ");
+    if (go_to_next_line)
+      print_word(ctx, "\n", 1);
+
+    if (ctx._M_max_length)
+      ctx._M_wordwrap = true;
+
+    print_word(ctx, "Error: ");
 
     // Print the error message
     assert(_M_text);
-    _M_print_string(_M_text);
-    _M_print_word(".\n");
+    print_string(ctx, _M_text, _M_parameters, _M_num_parameters);
+    print_word(ctx, ".\n", 2);
 
     // Emit descriptions of the objects involved in the operation
-    _M_wordwrap = false;
-    bool __has_noninteger_parameters = false;
-    for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
+    ctx._M_first_line = true;
+    ctx._M_wordwrap = false;
+    bool has_header = false;
+    for (unsigned int i = 0; i < _M_num_parameters; ++i)
       {
-	switch (_M_parameters[__i]._M_kind)
+	switch (_M_parameters[i]._M_kind)
 	  {
 	  case _Parameter::__iterator:
 	  case _Parameter::__sequence:
 	  case _Parameter::__instance:
 	  case _Parameter::__iterator_value_type:
-	    if (!__has_noninteger_parameters)
+	    if (!has_header)
 	      {
-		_M_first_line = true;
-		_M_print_word("\nObjects involved in the operation:\n");
-		__has_noninteger_parameters = true;
+		print_word(ctx, "\nObjects involved in the operation:\n");
+		has_header = true;
 	      }
-	    _M_parameters[__i]._M_print_description(this);
+	    print_description(ctx, _M_parameters[i]);
 	    break;
+
 	  default:
 	    break;
 	  }
@@ -867,172 +1059,43 @@ namespace __gnu_debug
     abort();
   }
 
-  template<typename _Tp>
-    void
-    _Error_formatter::_M_format_word(char* __buf,
-				     int __n __attribute__ ((__unused__)),
-				     const char* __fmt, _Tp __s) const throw ()
-    {
-#ifdef _GLIBCXX_USE_C99
-      std::snprintf(__buf, __n, __fmt, __s);
-#else
-      std::sprintf(__buf, __fmt, __s);
-#endif
-    }
-
+  // Deprecated methods kept for backward compatibility.
   void
-  _Error_formatter::_M_print_word(const char* __word) const
-  {
-    if (!_M_wordwrap)
-      {
-	fprintf(stderr, "%s", __word);
-	return;
-      }
-
-    size_t __length = strlen(__word);
-    if (__length == 0)
-      return;
-
-    size_t __visual_length
-      = __word[__length - 1] == '\n' ? __length - 1 : __length;
-    if (__visual_length == 0
-	|| (_M_column + __visual_length < _M_max_length)
-	|| (__visual_length >= _M_max_length && _M_column == 1))
-      {
-	// If this isn't the first line, indent
-	if (_M_column == 1 && !_M_first_line)
-	  {
-	    char __spacing[_M_indent + 1];
-	    for (int i = 0; i < _M_indent; ++i)
-	      __spacing[i] = ' ';
-	    __spacing[_M_indent] = '\0';
-	    fprintf(stderr, "%s", __spacing);
-	    _M_column += _M_indent;
-	  }
-
-	fprintf(stderr, "%s", __word);
-
-	if (__word[__length - 1] == '\n')
-	  {
-	    _M_first_line = false;
-	    _M_column = 1;
-	  }
-	else
-	  _M_column += __length;
-      }
-    else
-      {
-	_M_print_word("\n");
-	_M_print_word(__word);
-      }
-  }
+  _Error_formatter::_Parameter::_M_print_field(
+	const _Error_formatter*, const char*) const
+  { }
 
   void
-  _Error_formatter::
-  _M_print_string(const char* __string) const
-  {
-    const char* __start = __string;
-    const char* __finish = __start;
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+  _Error_formatter::_Parameter::_M_print_description(const _Error_formatter*) const
+  { }
 
-    while (*__start)
-      {
-	if (*__start != '%')
-	  {
-	    // [__start, __finish) denotes the next word
-	    __finish = __start;
-	    while (isalnum(*__finish))
-	      ++__finish;
-	    if (__start == __finish)
-	      ++__finish;
-	    if (isspace(*__finish))
-	      ++__finish;
-
-	    const ptrdiff_t __len = __finish - __start;
-	    assert(__len < __bufsize);
-	    memcpy(__buf, __start, __len);
-	    __buf[__len] = '\0';
-	    _M_print_word(__buf);
-	    __start = __finish;
-
-	    // Skip extra whitespace
-	    while (*__start == ' ')
-	      ++__start;
-
-	    continue;
-	  }
-
-	++__start;
-	assert(*__start);
-	if (*__start == '%')
-	  {
-	    _M_print_word("%");
-	    ++__start;
-	    continue;
-	  }
-
-	// Get the parameter number
-	assert(*__start >= '1' && *__start <= '9');
-	size_t __param_index = *__start - '0' - 1;
-	assert(__param_index < _M_num_parameters);
-	const auto& __param = _M_parameters[__param_index];
+  const _Error_formatter&
+  _Error_formatter::_M_message(_Debug_msg_id) const throw ()
+  { return *this; }
 
-	// '.' separates the parameter number from the field
-	// name, if there is one.
-	++__start;
-	if (*__start != '.')
-	  {
-	    assert(*__start == ';');
-	    ++__start;
-	    __buf[0] = '\0';
-	    if (__param._M_kind == _Parameter::__integer)
-	      {
-		_M_format_word(__buf, __bufsize, "%ld",
-			       __param._M_variant._M_integer._M_value);
-		_M_print_word(__buf);
-	      }
-	    else if (__param._M_kind == _Parameter::__string)
-	      _M_print_string(__param._M_variant._M_string._M_value);
-	    continue;
-	  }
+  template<typename _Tp>
+    void
+    _Error_formatter::_M_format_word(char*, int, const char*, _Tp)
+    const throw ()
+    { }
 
-	// Extract the field name we want
-	enum { __max_field_len = 16 };
-	char __field[__max_field_len];
-	int __field_idx = 0;
-	++__start;
-	while (*__start != ';')
-	  {
-	    assert(*__start);
-	    assert(__field_idx < __max_field_len-1);
-	    __field[__field_idx++] = *__start++;
-	  }
-	++__start;
-	__field[__field_idx] = 0;
+  void
+  _Error_formatter::_M_print_word(const char*) const
+  { }
 
-	__param._M_print_field(this, __field);
-      }
-  }
+  void
+  _Error_formatter::_M_print_string(const char*) const
+  { }
 
   void
   _Error_formatter::_M_get_max_length() const throw ()
-  {
-    const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
-    if (__nptr)
-      {
-	char* __endptr;
-	const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
-	if (*__nptr != '\0' && *__endptr == '\0')
-	  _M_max_length = __ret;
-      }
-  }
+  { }
 
   // Instantiations.
   template
     void
     _Error_formatter::_M_format_word(char*, int, const char*,
-				     const void*) const;
+                                    const void*) const;
 
   template
     void
@@ -1041,10 +1104,10 @@ namespace __gnu_debug
   template
     void
     _Error_formatter::_M_format_word(char*, int, const char*,
-				     std::size_t) const;
+                                    std::size_t) const;
 
   template
     void
     _Error_formatter::_M_format_word(char*, int, const char*,
-				     const char*) const;
+                                    const char*) const;
 } // namespace __gnu_debug

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-08 21:02   ` François Dumont
@ 2015-09-14 18:27     ` François Dumont
  2015-09-15 23:08       ` Jonathan Wakely
  0 siblings, 1 reply; 9+ messages in thread
From: François Dumont @ 2015-09-14 18:27 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1550 bytes --]

On 08/09/2015 22:47, François Dumont wrote:
> On 07/09/2015 13:03, Jonathan Wakely wrote:
>> On 05/09/15 22:53 +0200, François Dumont wrote:
>>>    I remember Paolo saying once that we were not guarantiing any abi
>>> compatibility for debug mode. I haven't found any section for
>>> unversioned symbols in gnu.ver so I simply uncomment the global export.
>> There is no section, because all exported symbols are versioned.
>>
>> It's OK if objects compiled with Debug Mode using one version of GCC
>> don't link to objects compiled with Debug Mode using a different
>> version of GCC, but you can't change the exported symbols in the DSO.
>>
>>
>> Your changelog doesn't include the changes to config/abi/pre/gnu.ver,
>> but those changes are not OK anyway, they fail the abi-check:
>>
>> FAIL: libstdc++-abi/abi_check
>>
>>                === libstdc++ Summary ===
>>
>> # of unexpected failures        1
>>
>>
> Sorry, I though policy regarding debug mode symbols was even more relax.
> It is not so here is another patch that doesn"t break abi checks.
>
> I eventually made all methods that should not be used deprecated, they
> were normally not used explicitely anyway. Their implementation is now
> empty. I just needed to add a symbol for the not const _M_message method
> which is the correct signature.
>
> François
>
I eventually considered doing it without impacting exported symbols. I
just kept the const qualifier on _M_messages and introduced a const_cast
in the implementation.

Is it ok to commit with this version ?

François


[-- Attachment #2: debug.patch --]
[-- Type: text/x-patch, Size: 32482 bytes --]

diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h
index f0ac694..6e56c8f 100644
--- a/libstdc++-v3/include/debug/formatter.h
+++ b/libstdc++-v3/include/debug/formatter.h
@@ -133,6 +133,13 @@ namespace __gnu_debug
 
   class _Error_formatter
   {
+    // Tags denoting the type of parameter for construction
+    struct _Is_iterator { };
+    struct _Is_iterator_value_type { };
+    struct _Is_sequence { };
+    struct _Is_instance { };
+
+  public:
     /// Whether an iterator is constant, mutable, or unknown
     enum _Constness
     {
@@ -154,13 +161,6 @@ namespace __gnu_debug
       __last_state
     };
 
-    // 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
     {
@@ -376,15 +376,16 @@ namespace __gnu_debug
 
       void
       _M_print_field(const _Error_formatter* __formatter,
-		     const char* __name) const;
+		     const char* __name) const _GLIBCXX_DEPRECATED;
 
       void
-      _M_print_description(const _Error_formatter* __formatter) const;
+      _M_print_description(const _Error_formatter* __formatter)
+	const _GLIBCXX_DEPRECATED;
     };
 
     template<typename _Iterator>
-      const _Error_formatter&
-      _M_iterator(const _Iterator& __it, const char* __name = 0)  const
+      _Error_formatter&
+      _M_iterator(const _Iterator& __it, const char* __name = 0)
       {
 	if (_M_num_parameters < std::size_t(__max_parameters))
 	  _M_parameters[_M_num_parameters++] = _Parameter(__it, __name,
@@ -393,57 +394,59 @@ namespace __gnu_debug
       }
 
     template<typename _Iterator>
-      const _Error_formatter&
+      _Error_formatter&
       _M_iterator_value_type(const _Iterator& __it,
-			     const char* __name = 0)  const
+			     const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __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
+    _Error_formatter&
+    _M_integer(long __value, const char* __name = 0)
     {
-      if (_M_num_parameters < std::size_t(__max_parameters))
+      if (_M_num_parameters < __max_parameters)
 	_M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
       return *this;
     }
 
-    const _Error_formatter&
-    _M_string(const char* __value, const char* __name = 0) const
+    _Error_formatter&
+    _M_string(const char* __value, const char* __name = 0)
     {
-      if (_M_num_parameters < std::size_t(__max_parameters))
+      if (_M_num_parameters < __max_parameters)
 	_M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
       return *this;
     }
 
     template<typename _Sequence>
-      const _Error_formatter&
-      _M_sequence(const _Sequence& __seq, const char* __name = 0) const
+      _Error_formatter&
+      _M_sequence(const _Sequence& __seq, const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __max_parameters)
 	  _M_parameters[_M_num_parameters++] = _Parameter(__seq, __name,
 							  _Is_sequence());
 	return *this;
       }
 
     template<typename _Type>
-      const _Error_formatter&
-      _M_instance(const _Type& __inst, const char* __name = 0) const
+      _Error_formatter&
+      _M_instance(const _Type& __inst, const char* __name = 0)
       {
-	if (_M_num_parameters < std::size_t(__max_parameters))
+	if (_M_num_parameters < __max_parameters)
 	  _M_parameters[_M_num_parameters++] = _Parameter(__inst, __name,
 							  _Is_instance());
 	return *this;
       }
 
-    const _Error_formatter&
-    _M_message(const char* __text) const
+    _Error_formatter&
+    _M_message(const char* __text)
     { _M_text = __text; return *this; }
 
-    const _Error_formatter&
+    // Kept const qualifier for backward compatibility, to keep the same
+    // exported symbol.
+    _Error_formatter&
     _M_message(_Debug_msg_id __id) const throw ();
 
     _GLIBCXX_NORETURN void
@@ -451,40 +454,38 @@ namespace __gnu_debug
 
     template<typename _Tp>
       void
-      _M_format_word(char*, int, const char*, _Tp) const throw ();
+      _M_format_word(char*, int, const char*, _Tp)
+      const throw () _GLIBCXX_DEPRECATED;
 
     void
-    _M_print_word(const char* __word) const;
+    _M_print_word(const char* __word) const _GLIBCXX_DEPRECATED;
 
     void
-    _M_print_string(const char* __string) const;
+    _M_print_string(const char* __string) const _GLIBCXX_DEPRECATED;
 
   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(); }
+    _Error_formatter(const char* __file, unsigned int __line)
+    : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0)
+    { }
 
     void
-    _M_get_max_length() const throw ();
+    _M_get_max_length() const throw () _GLIBCXX_DEPRECATED;
 
     enum { __max_parameters = 9 };
 
     const char*		_M_file;
-    std::size_t		_M_line;
-    mutable _Parameter	_M_parameters[__max_parameters];
-    mutable std::size_t	_M_num_parameters;
-    mutable const char*	_M_text;
-    mutable std::size_t	_M_max_length;
-    enum { _M_indent = 4 } ;
-    mutable std::size_t	_M_column;
-    mutable bool	_M_first_line;
-    mutable bool	_M_wordwrap;
+    unsigned int	_M_line;
+    _Parameter		_M_parameters[__max_parameters];
+    unsigned int	_M_num_parameters;
+    const char*		_M_text;
 
   public:
-    static _Error_formatter
-    _M_at(const char* __file, std::size_t __line)
-    { return _Error_formatter(__file, __line); }
+    static _Error_formatter&
+    _M_at(const char* __file, unsigned int __line)
+    {
+      static _Error_formatter __formatter(__file, __line);
+      return __formatter;
+    }
   };
 } // namespace __gnu_debug
 
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index d3f8cae..737d978 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -22,18 +22,19 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // <http://www.gnu.org/licenses/>.
 
-#include <debug/debug.h>
+#include <bits/move.h>
+#include <bits/stl_iterator_base_types.h>
+
+#include <debug/formatter.h>
 #include <debug/safe_base.h>
 #include <debug/safe_unordered_base.h>
 #include <debug/safe_iterator.h>
 #include <debug/safe_local_iterator.h>
-#include <algorithm>
+
 #include <cassert>
-#include <cstring>
-#include <cctype>
-#include <cstdio>
-#include <cstdlib>
-#include <functional>
+
+#include <algorithm> // for std::min
+#include <functional> // for _Hash_impl
 
 #include <cxxabi.h> // for __cxa_demangle
 
@@ -526,202 +527,236 @@ namespace __gnu_debug
 
 namespace
 {
+  using _Error_formatter = __gnu_debug::_Error_formatter;
+  using _Parameter = __gnu_debug::_Error_formatter::_Parameter;
+
+  template<typename _Tp>
+    int
+    format_word(char* buf, int n, const char* fmt, _Tp s)
+    { return std::min(__builtin_snprintf(buf, n, fmt, s), n - 1); }
+
   void
-  print_type(const __gnu_debug::_Error_formatter* __formatter,
-	     const type_info* __info,
-	     const char* __unknown_name)
+  get_max_length(std::size_t& max_length)
   {
-    if (!__info)
-      __formatter->_M_print_word(__unknown_name);
-    else
+    const char* nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
+    if (nptr)
       {
-	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);
+	char* endptr;
+	const unsigned long ret = std::strtoul(nptr, &endptr, 0);
+	if (*nptr != '\0' && *endptr == '\0')
+	  max_length = ret;
       }
   }
 
-  bool
-  print_field(
-    const __gnu_debug::_Error_formatter* __formatter,
-    const char* __name,
-    const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
+  struct PrintContext
   {
-    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;
-  }
+    PrintContext()
+      : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false)
+    { get_max_length(_M_max_length); }
+
+    std::size_t	_M_max_length;
+    enum { _M_indent = 4 } ;
+    std::size_t	_M_column;
+    bool	_M_first_line;
+    bool	_M_wordwrap;
+  };
 
-  bool
-  print_field(
-    const __gnu_debug::_Error_formatter* __formatter,
-    const char* __name,
-    const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  void
+  print_word(PrintContext& ctx, const char* word,
+	     std::ptrdiff_t count = -1)
   {
-    const __gnu_debug::_Error_formatter::_Parameter::_Type& __type = __variant;
-    if (print_field(__formatter, __name, __type))
-      { }
-    else if (strcmp(__name, "address") == 0)
+    size_t length = count >= 0 ? count : __builtin_strlen(word);
+    if (length == 0)
+      return;
+
+    // Consider first '\n' at begining cause it impacts column.
+    if (word[0] == '\n')
       {
-	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;
+	fprintf(stderr, "\n");
+	ctx._M_column = 1;
+	++word;
+	--length;
 
-    return true;
-  }
+	if (length == 0)
+	  return;
+      }
 
-  void
-  print_description(
-	const __gnu_debug::_Error_formatter* __formatter,
-	const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
-  {
-    if (__variant._M_name)
+    size_t visual_length
+      = isspace(word[length - 1]) ? length - 1 : length;
+    if (visual_length == 0
+	|| !ctx._M_wordwrap
+	|| (ctx._M_column + visual_length < ctx._M_max_length)
+	|| (visual_length >= ctx._M_max_length && ctx._M_column == 1))
       {
-	const int __bufsize = 64;
-	char __buf[__bufsize];
-	__formatter->_M_format_word(__buf, __bufsize, "\"%s\"",
-				    __variant._M_name);
-	__formatter->_M_print_word(__buf);
-      }
+	// If this isn't the first line, indent
+	if (ctx._M_column == 1 && !ctx._M_first_line)
+	  {
+	    char spacing[ctx._M_indent + 1];
+	    for (int i = 0; i < ctx._M_indent; ++i)
+	      spacing[i] = ' ';
+	    spacing[ctx._M_indent] = '\0';
+	    fprintf(stderr, "%s", spacing);
+	    ctx._M_column += ctx._M_indent;
+	  }
 
-    __formatter->_M_print_word(" {\n");
+	int written = fprintf(stderr, "%s", word);
 
-    if (__variant._M_type)
+	if (word[length - 1] == '\n')
+	  {
+	    ctx._M_first_line = false;
+	    ctx._M_column = 1;
+	  }
+	else
+	  ctx._M_column += written;
+      }
+    else
       {
-	__formatter->_M_print_word("  type = ");
-	print_type(__formatter, __variant._M_type, "<unknown type>");
-	__formatter->_M_print_word(";\n");
+	print_word(ctx, "\n", 1);
+	print_word(ctx, word, count);
       }
   }
 
-
   void
-  print_description(
-	const __gnu_debug::_Error_formatter* __formatter,
-	const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
+  print_type(PrintContext& ctx,
+	     const type_info* info,
+	     const char* unknown_name)
   {
-    const int __bufsize = 64;
-    char __buf[__bufsize];
+    if (!info)
+      print_word(ctx, unknown_name);
+    else
+      {
+	int status;
+	char* demangled_name =
+	  __cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status);
+	print_word(ctx, status == 0 ? demangled_name : info->name());
+	free(demangled_name);
+      }
+  }
 
-    if (__variant._M_name)
+  bool
+  print_field(PrintContext& ctx,
+	      const char* name, const _Parameter::_Type& type)
+  {
+    if (__builtin_strcmp(name, "name") == 0)
       {
-	__formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
-				    __variant._M_name);
-	__formatter->_M_print_word(__buf);
+	assert(type._M_name);
+	print_word(ctx, type._M_name);
       }
+    else if (__builtin_strcmp(name, "type") == 0)
+      print_type(ctx, type._M_type, "<unknown type>");
+    else
+      return false;
 
-    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
-				__variant._M_address);
-    __formatter->_M_print_word(__buf);
+    return true;
+  }
 
-    if (__variant._M_type)
+  bool
+  print_field(PrintContext& ctx,
+	      const char* name, const _Parameter::_Instance& inst)
+  {
+    const _Parameter::_Type& type = inst;
+    if (print_field(ctx, name, type))
+      { }
+    else if (__builtin_strcmp(name, "address") == 0)
       {
-	__formatter->_M_print_word("  type = ");
-	print_type(__formatter, __variant._M_type, "<unknown type>");
+	char buf[64];
+	int ret = __builtin_sprintf(buf, "%p", inst._M_address);
+	print_word(ctx, buf, ret);
       }
+    else
+      return false;
+
+    return true;
   }
-}
 
-namespace __gnu_debug
-{
   void
-  _Error_formatter::_Parameter::
-  _M_print_field(const _Error_formatter* __formatter, const char* __name) const
+  print_field(PrintContext& ctx, const _Parameter& param, const char* name)
   {
-    assert(this->_M_kind != _Parameter::__unused_param);
-    const int __bufsize = 64;
-    char __buf[__bufsize];
+    assert(param._M_kind != _Parameter::__unused_param);
+    const int bufsize = 64;
+    char buf[bufsize];
 
-    switch (_M_kind)
+    const auto& variant = param._M_variant;
+    switch (param._M_kind)
     {
-    case __iterator:
-      if (print_field(__formatter, __name, _M_variant._M_iterator))
-	{ }
-      else if (strcmp(__name, "constness") == 0)
-	{
-	  static const char* __constness_names[__last_constness] =
-	    {
-	      "<unknown>",
-	      "constant",
-	      "mutable"
-	    };
-	  __formatter->_M_print_word(__constness_names[_M_variant.
-						       _M_iterator.
-						       _M_constness]);
-	}
-      else if (strcmp(__name, "state") == 0)
-	{
-	  static const char* __state_names[__last_state] =
-	    {
-	      "<unknown>",
-	      "singular",
-	      "dereferenceable (start-of-sequence)",
-	      "dereferenceable",
-	      "past-the-end",
-	      "before-begin"
-	    };
-	  __formatter->_M_print_word(__state_names[_M_variant.
-						   _M_iterator._M_state]);
-	}
-      else if (strcmp(__name, "sequence") == 0)
-	{
-	  assert(_M_variant._M_iterator._M_sequence);
-	  __formatter->_M_format_word(__buf, __bufsize, "%p",
-				      _M_variant._M_iterator._M_sequence);
-	  __formatter->_M_print_word(__buf);
-	}
-      else if (strcmp(__name, "seq_type") == 0)
-	print_type(__formatter, _M_variant._M_iterator._M_seq_type,
-		   "<unknown seq_type>");
-      else
-	assert(false);
+    case _Parameter::__iterator:
+      {
+	const auto& iterator = variant._M_iterator;
+	if (print_field(ctx, name, iterator))
+	  { }
+	else if (__builtin_strcmp(name, "constness") == 0)
+	  {
+	    static const char*
+	      constness_names[_Error_formatter::__last_constness] =
+	      {
+		"<unknown>",
+		"constant",
+		"mutable"
+	      };
+	    print_word(ctx, constness_names[iterator._M_constness]);
+	  }
+	else if (__builtin_strcmp(name, "state") == 0)
+	  {
+	    static const char*
+	      state_names[_Error_formatter::__last_state] =
+	      {
+		"<unknown>",
+		"singular",
+		"dereferenceable (start-of-sequence)",
+		"dereferenceable",
+		"past-the-end",
+		"before-begin"
+	      };
+	    print_word(ctx, state_names[iterator._M_state]);
+	  }
+	else if (__builtin_strcmp(name, "sequence") == 0)
+	  {
+	    assert(iterator._M_sequence);
+	    int written = __builtin_sprintf(buf, "%p", iterator._M_sequence);
+	    print_word(ctx, buf, written);
+	  }
+	else if (__builtin_strcmp(name, "seq_type") == 0)
+	  print_type(ctx, iterator._M_seq_type, "<unknown seq_type>");
+	else
+	  assert(false);
+      }
       break;
-    case __sequence:
-      if (!print_field(__formatter, __name, _M_variant._M_sequence))
+
+    case _Parameter::__sequence:
+      if (!print_field(ctx, name, variant._M_sequence))
 	assert(false);
       break;
-    case __integer:
-      if (strcmp(__name, "name") == 0)
+
+    case _Parameter::__integer:
+      if (__builtin_strcmp(name, "name") == 0)
 	{
-	  assert(_M_variant._M_integer._M_name);
-	  __formatter->_M_print_word(_M_variant._M_integer._M_name);
+	  assert(variant._M_integer._M_name);
+	  print_word(ctx, variant._M_integer._M_name);
 	}
       else
 	assert(false);
       break;
-    case __string:
-      if (strcmp(__name, "name") == 0)
+
+    case _Parameter::__string:
+      if (__builtin_strcmp(name, "name") == 0)
 	{
-	  assert(_M_variant._M_string._M_name);
-	  __formatter->_M_print_word(_M_variant._M_string._M_name);
+	  assert(variant._M_string._M_name);
+	  print_word(ctx, variant._M_string._M_name);
 	}
       else
 	assert(false);
       break;
-    case __instance:
-      if (!print_field(__formatter, __name, _M_variant._M_instance))
+
+    case _Parameter::__instance:
+      if (!print_field(ctx, name, variant._M_instance))
 	assert(false);
       break;
-    case __iterator_value_type:
-      if (!print_field(__formatter, __name, _M_variant._M_iterator_value_type))
+
+    case _Parameter::__iterator_value_type:
+      if (!print_field(ctx, name, variant._M_iterator_value_type))
 	assert(false);
       break;
+
     default:
       assert(false);
       break;
@@ -729,136 +764,296 @@ namespace __gnu_debug
   }
 
   void
-  _Error_formatter::_Parameter::
-  _M_print_description(const _Error_formatter* __formatter) const
+  print_description(PrintContext& ctx, const _Parameter::_Type& type)
+  {
+    if (type._M_name)
+      {
+	const int bufsize = 64;
+	char buf[bufsize];
+	int written
+	  = format_word(buf, bufsize, "\"%s\"", type._M_name);
+	print_word(ctx, buf, written);
+      }
+
+    print_word(ctx, " {\n");
+
+    if (type._M_type)
+      {
+	print_word(ctx, "  type = ");
+	print_type(ctx, type._M_type, "<unknown type>");
+	print_word(ctx, ";\n");
+      }
+  }
+
+  void
+  print_description(PrintContext& ctx, const _Parameter::_Instance& inst)
   {
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+    const int bufsize = 64;
+    char buf[bufsize];
 
-    switch (_M_kind)
+    if (inst._M_name)
       {
-      case __iterator:
-	__formatter->_M_print_word("iterator ");
-	print_description(__formatter, _M_variant._M_iterator);
+	int written
+	  = format_word(buf, bufsize, "\"%s\" ", inst._M_name);
+	print_word(ctx, buf, written);
+      }
 
-	if (_M_variant._M_iterator._M_type)
-	  {
-	    if (_M_variant._M_iterator._M_constness != __unknown_constness)
-	      {
-		__formatter->_M_print_word(" (");
-		_M_print_field(__formatter, "constness");
-		__formatter->_M_print_word(" iterator)");
-	      }
-	    __formatter->_M_print_word(";\n");
-	  }
+    int written
+      = __builtin_sprintf(buf, "@ 0x%p {\n", inst._M_address);
+    print_word(ctx, buf, written);
 
-	if (_M_variant._M_iterator._M_state != __unknown_state)
-	  {
-	    __formatter->_M_print_word("  state = ");
-	    _M_print_field(__formatter, "state");
-	    __formatter->_M_print_word(";\n");
-	  }
+    if (inst._M_type)
+      {
+	print_word(ctx, "  type = ");
+	print_type(ctx, inst._M_type, "<unknown type>");
+      }
+  }
 
-	if (_M_variant._M_iterator._M_sequence)
-	  {
-	    __formatter->_M_print_word("  references sequence ");
-	    if (_M_variant._M_iterator._M_seq_type)
-	      {
-		__formatter->_M_print_word("with type `");
-		_M_print_field(__formatter, "seq_type");
-		__formatter->_M_print_word("' ");
-	      }
+  void
+  print_description(PrintContext& ctx, const _Parameter& param)
+  {
+    const int bufsize = 128;
+    char buf[bufsize];
 
-	    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n",
-					_M_variant._M_iterator._M_sequence);
-	    __formatter->_M_print_word(__buf);
-	  }
+    const auto& variant = param._M_variant;
+    switch (param._M_kind)
+      {
+      case _Parameter::__iterator:
+	{
+	  const auto& ite = variant._M_iterator;
+
+	  print_word(ctx, "iterator ");
+	  print_description(ctx, ite);
 
-	__formatter->_M_print_word("}\n");
+	  if (ite._M_type)
+	    {
+	      if (ite._M_constness != _Error_formatter::__unknown_constness)
+		{
+		  print_word(ctx, " (");
+		  print_field(ctx, param, "constness");
+		  print_word(ctx, " iterator)");
+		}
+
+	      print_word(ctx, ";\n");
+	    }
+
+	  if (ite._M_state != _Error_formatter::__unknown_state)
+	    {
+	      print_word(ctx, "  state = ");
+	      print_field(ctx, param, "state");
+	      print_word(ctx, ";\n");
+	    }
+
+	  if (ite._M_sequence)
+	    {
+	      print_word(ctx, "  references sequence ");
+	      if (ite._M_seq_type)
+		{
+		  print_word(ctx, "with type '");
+		  print_field(ctx, param, "seq_type");
+		  print_word(ctx, "' ");
+		}
+
+	      int written
+		= __builtin_sprintf(buf, "@ 0x%p\n", ite._M_sequence);
+	      print_word(ctx, buf, written);
+	    }
+
+	  print_word(ctx, "}\n", 2);
+	}
 	break;
-      case __sequence:
-	__formatter->_M_print_word("sequence ");
-	print_description(__formatter, _M_variant._M_sequence);
 
-	if (_M_variant._M_sequence._M_type)
-	  __formatter->_M_print_word(";\n");
+      case _Parameter::__sequence:
+	print_word(ctx, "sequence ");
+	print_description(ctx, variant._M_sequence);
 
-	__formatter->_M_print_word("}\n");
+	if (variant._M_sequence._M_type)
+	  print_word(ctx, ";\n", 2);
+
+	print_word(ctx, "}\n", 2);
 	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");
+      case _Parameter::__instance:
+	print_word(ctx, "instance ");
+	print_description(ctx, variant._M_instance);
+
+	if (variant._M_instance._M_type)
+	  print_word(ctx, ";\n", 2);
 
-	__formatter->_M_print_word("}\n");
+	print_word(ctx, "}\n", 2);
 	break;
-      case __iterator_value_type:
-	__formatter->_M_print_word("iterator::value_type ");
-	print_description(__formatter, _M_variant._M_iterator_value_type);
-	__formatter->_M_print_word("}\n");
+
+      case _Parameter::__iterator_value_type:
+	print_word(ctx, "iterator::value_type ");
+	print_description(ctx, variant._M_iterator_value_type);
+	print_word(ctx, "}\n", 2);
 	break;
+
       default:
 	break;
       }
   }
 
-  const _Error_formatter&
+  void
+  print_string(PrintContext& ctx, const char* string,
+	       const _Parameter* parameters, std::size_t num_parameters)
+  {
+    const char* start = string;
+    const int bufsize = 128;
+    char buf[bufsize];
+    int bufindex = 0;
+
+    while (*start)
+      {
+	if (isspace(*start))
+	  {
+	    buf[bufindex++] = *start++;
+	    buf[bufindex] = '\0';
+	    print_word(ctx, buf, bufindex);
+	    bufindex = 0;
+	    continue;
+	  }
+
+	if (*start != '%')
+	  {
+	    // Normal char.
+	    buf[bufindex++] = *start++;
+	    continue;
+	  }
+
+	if (*++start == '%')
+	  {
+	    // Escaped '%'
+	    buf[bufindex++] = *start++;
+	    continue;
+	  }
+
+	// We are on a parameter property reference, we need to flush buffer
+	// first.
+	if (bufindex != 0)
+	  {
+	    buf[bufindex] = '\0';
+	    print_word(ctx, buf, bufindex);
+	    bufindex = 0;
+	  }
+
+	// Get the parameter number
+	assert(*start >= '1' && *start <= '9');
+	size_t param_index = *start - '0' - 1;
+	assert(param_index < num_parameters);
+	const auto& param = parameters[param_index];
+
+	// '.' separates the parameter number from the field
+	// name, if there is one.
+	++start;
+	if (*start != '.')
+	  {
+	    assert(*start == ';');
+	    ++start;
+	    if (param._M_kind == _Parameter::__integer)
+	      {
+		int written
+		  = __builtin_sprintf(buf, "%ld",
+				      param._M_variant._M_integer._M_value);
+		print_word(ctx, buf, written);
+	      }
+	    else if (param._M_kind == _Parameter::__string)
+	      print_string(ctx, param._M_variant._M_string._M_value,
+			   parameters, num_parameters);
+	    continue;
+	  }
+
+	// Extract the field name we want
+	const int max_field_len = 16;
+	char field[max_field_len];
+	int field_idx = 0;
+	++start;
+	while (*start != ';')
+	  {
+	    assert(*start);
+	    assert(field_idx < max_field_len - 1);
+	    field[field_idx++] = *start++;
+	  }
+	++start;
+	field[field_idx] = '\0';
+
+	print_field(ctx, param, field);
+      }
+
+    // Might need to flush.
+    if (bufindex)
+      {
+	buf[bufindex] = '\0';
+	print_word(ctx, buf, bufindex);
+      }
+  }
+}
+
+namespace __gnu_debug
+{
+  _Error_formatter&
   _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
-  { return this->_M_message(_S_debug_messages[__id]); }
+  {
+    return const_cast<_Error_formatter*>(this)
+      ->_M_message(_S_debug_messages[__id]);
+  }
 
   void
   _Error_formatter::_M_error() const
   {
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+    const int bufsize = 128;
+    char buf[bufsize];
 
     // Emit file & line number information
-    _M_column = 1;
-    _M_wordwrap = false;
+    bool go_to_next_line = false;
+    PrintContext ctx;
     if (_M_file)
       {
-	_M_format_word(__buf, __bufsize, "%s:", _M_file);
-	_M_print_word(__buf);
-	_M_column += strlen(__buf);
+	int written = format_word(buf, bufsize, "%s:", _M_file);
+	print_word(ctx, buf, written);
+	go_to_next_line = true;
       }
 
     if (_M_line > 0)
       {
-	_M_format_word(__buf, __bufsize, "%u:", _M_line);
-	_M_print_word(__buf);
-	_M_column += strlen(__buf);
+	int written = __builtin_sprintf(buf, "%u:", _M_line);
+	print_word(ctx, buf, written);
+	go_to_next_line = true;
       }
 
-    if (_M_max_length)
-      _M_wordwrap = true;
-    _M_print_word("error: ");
+    if (go_to_next_line)
+      print_word(ctx, "\n", 1);
+
+    if (ctx._M_max_length)
+      ctx._M_wordwrap = true;
+
+    print_word(ctx, "Error: ");
 
     // Print the error message
     assert(_M_text);
-    _M_print_string(_M_text);
-    _M_print_word(".\n");
+    print_string(ctx, _M_text, _M_parameters, _M_num_parameters);
+    print_word(ctx, ".\n", 2);
 
     // Emit descriptions of the objects involved in the operation
-    _M_wordwrap = false;
-    bool __has_noninteger_parameters = false;
-    for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
+    ctx._M_first_line = true;
+    ctx._M_wordwrap = false;
+    bool has_header = false;
+    for (unsigned int i = 0; i < _M_num_parameters; ++i)
       {
-	switch (_M_parameters[__i]._M_kind)
+	switch (_M_parameters[i]._M_kind)
 	  {
 	  case _Parameter::__iterator:
 	  case _Parameter::__sequence:
 	  case _Parameter::__instance:
 	  case _Parameter::__iterator_value_type:
-	    if (!__has_noninteger_parameters)
+	    if (!has_header)
 	      {
-		_M_first_line = true;
-		_M_print_word("\nObjects involved in the operation:\n");
-		__has_noninteger_parameters = true;
+		print_word(ctx, "\nObjects involved in the operation:\n");
+		has_header = true;
 	      }
-	    _M_parameters[__i]._M_print_description(this);
+	    print_description(ctx, _M_parameters[i]);
 	    break;
+
 	  default:
 	    break;
 	  }
@@ -867,172 +1062,39 @@ namespace __gnu_debug
     abort();
   }
 
-  template<typename _Tp>
-    void
-    _Error_formatter::_M_format_word(char* __buf,
-				     int __n __attribute__ ((__unused__)),
-				     const char* __fmt, _Tp __s) const throw ()
-    {
-#ifdef _GLIBCXX_USE_C99
-      std::snprintf(__buf, __n, __fmt, __s);
-#else
-      std::sprintf(__buf, __fmt, __s);
-#endif
-    }
-
+  // Deprecated methods kept for backward compatibility.
   void
-  _Error_formatter::_M_print_word(const char* __word) const
-  {
-    if (!_M_wordwrap)
-      {
-	fprintf(stderr, "%s", __word);
-	return;
-      }
-
-    size_t __length = strlen(__word);
-    if (__length == 0)
-      return;
-
-    size_t __visual_length
-      = __word[__length - 1] == '\n' ? __length - 1 : __length;
-    if (__visual_length == 0
-	|| (_M_column + __visual_length < _M_max_length)
-	|| (__visual_length >= _M_max_length && _M_column == 1))
-      {
-	// If this isn't the first line, indent
-	if (_M_column == 1 && !_M_first_line)
-	  {
-	    char __spacing[_M_indent + 1];
-	    for (int i = 0; i < _M_indent; ++i)
-	      __spacing[i] = ' ';
-	    __spacing[_M_indent] = '\0';
-	    fprintf(stderr, "%s", __spacing);
-	    _M_column += _M_indent;
-	  }
-
-	fprintf(stderr, "%s", __word);
-
-	if (__word[__length - 1] == '\n')
-	  {
-	    _M_first_line = false;
-	    _M_column = 1;
-	  }
-	else
-	  _M_column += __length;
-      }
-    else
-      {
-	_M_print_word("\n");
-	_M_print_word(__word);
-      }
-  }
+  _Error_formatter::_Parameter::_M_print_field(
+	const _Error_formatter*, const char*) const
+  { }
 
   void
-  _Error_formatter::
-  _M_print_string(const char* __string) const
-  {
-    const char* __start = __string;
-    const char* __finish = __start;
-    const int __bufsize = 128;
-    char __buf[__bufsize];
+  _Error_formatter::_Parameter::_M_print_description(const _Error_formatter*) const
+  { }
 
-    while (*__start)
-      {
-	if (*__start != '%')
-	  {
-	    // [__start, __finish) denotes the next word
-	    __finish = __start;
-	    while (isalnum(*__finish))
-	      ++__finish;
-	    if (__start == __finish)
-	      ++__finish;
-	    if (isspace(*__finish))
-	      ++__finish;
-
-	    const ptrdiff_t __len = __finish - __start;
-	    assert(__len < __bufsize);
-	    memcpy(__buf, __start, __len);
-	    __buf[__len] = '\0';
-	    _M_print_word(__buf);
-	    __start = __finish;
-
-	    // Skip extra whitespace
-	    while (*__start == ' ')
-	      ++__start;
-
-	    continue;
-	  }
-
-	++__start;
-	assert(*__start);
-	if (*__start == '%')
-	  {
-	    _M_print_word("%");
-	    ++__start;
-	    continue;
-	  }
-
-	// Get the parameter number
-	assert(*__start >= '1' && *__start <= '9');
-	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.
-	++__start;
-	if (*__start != '.')
-	  {
-	    assert(*__start == ';');
-	    ++__start;
-	    __buf[0] = '\0';
-	    if (__param._M_kind == _Parameter::__integer)
-	      {
-		_M_format_word(__buf, __bufsize, "%ld",
-			       __param._M_variant._M_integer._M_value);
-		_M_print_word(__buf);
-	      }
-	    else if (__param._M_kind == _Parameter::__string)
-	      _M_print_string(__param._M_variant._M_string._M_value);
-	    continue;
-	  }
+  template<typename _Tp>
+    void
+    _Error_formatter::_M_format_word(char*, int, const char*, _Tp)
+    const throw ()
+    { }
 
-	// Extract the field name we want
-	enum { __max_field_len = 16 };
-	char __field[__max_field_len];
-	int __field_idx = 0;
-	++__start;
-	while (*__start != ';')
-	  {
-	    assert(*__start);
-	    assert(__field_idx < __max_field_len-1);
-	    __field[__field_idx++] = *__start++;
-	  }
-	++__start;
-	__field[__field_idx] = 0;
+  void
+  _Error_formatter::_M_print_word(const char*) const
+  { }
 
-	__param._M_print_field(this, __field);
-      }
-  }
+  void
+  _Error_formatter::_M_print_string(const char*) const
+  { }
 
   void
   _Error_formatter::_M_get_max_length() const throw ()
-  {
-    const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
-    if (__nptr)
-      {
-	char* __endptr;
-	const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
-	if (*__nptr != '\0' && *__endptr == '\0')
-	  _M_max_length = __ret;
-      }
-  }
+  { }
 
   // Instantiations.
   template
     void
     _Error_formatter::_M_format_word(char*, int, const char*,
-				     const void*) const;
+                                    const void*) const;
 
   template
     void
@@ -1041,10 +1103,10 @@ namespace __gnu_debug
   template
     void
     _Error_formatter::_M_format_word(char*, int, const char*,
-				     std::size_t) const;
+                                    std::size_t) const;
 
   template
     void
     _Error_formatter::_M_format_word(char*, int, const char*,
-				     const char*) const;
+                                    const char*) const;
 } // namespace __gnu_debug


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-14 18:27     ` François Dumont
@ 2015-09-15 23:08       ` Jonathan Wakely
  2015-09-17 19:31         ` François Dumont
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2015-09-15 23:08 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 14/09/15 20:26 +0200, François Dumont wrote:
>On 08/09/2015 22:47, François Dumont wrote:
>> On 07/09/2015 13:03, Jonathan Wakely wrote:
>>> On 05/09/15 22:53 +0200, François Dumont wrote:
>>>>    I remember Paolo saying once that we were not guarantiing any abi
>>>> compatibility for debug mode. I haven't found any section for
>>>> unversioned symbols in gnu.ver so I simply uncomment the global export.
>>> There is no section, because all exported symbols are versioned.
>>>
>>> It's OK if objects compiled with Debug Mode using one version of GCC
>>> don't link to objects compiled with Debug Mode using a different
>>> version of GCC, but you can't change the exported symbols in the DSO.
>>>
>>>
>>> Your changelog doesn't include the changes to config/abi/pre/gnu.ver,
>>> but those changes are not OK anyway, they fail the abi-check:
>>>
>>> FAIL: libstdc++-abi/abi_check
>>>
>>>                === libstdc++ Summary ===
>>>
>>> # of unexpected failures        1
>>>
>>>
>> Sorry, I though policy regarding debug mode symbols was even more relax.
>> It is not so here is another patch that doesn"t break abi checks.
>>
>> I eventually made all methods that should not be used deprecated, they
>> were normally not used explicitely anyway. Their implementation is now
>> empty. I just needed to add a symbol for the not const _M_message method
>> which is the correct signature.
>>
>> François
>>
>I eventually considered doing it without impacting exported symbols. I
>just kept the const qualifier on _M_messages and introduced a const_cast
>in the implementation.
>
>Is it ok to commit with this version ?

The changes look OK now (assuming it passes 'make check-abi') but what
does it actually do?

Does it significantly improve the output?

(I haven't found time to apply the patch and test it myself, sorry).

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-15 23:08       ` Jonathan Wakely
@ 2015-09-17 19:31         ` François Dumont
  0 siblings, 0 replies; 9+ messages in thread
From: François Dumont @ 2015-09-17 19:31 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

On 15/09/2015 23:57, Jonathan Wakely wrote:
> On 14/09/15 20:26 +0200, François Dumont wrote:
>> On 08/09/2015 22:47, François Dumont wrote:
>>> On 07/09/2015 13:03, Jonathan Wakely wrote:
>>>> On 05/09/15 22:53 +0200, François Dumont wrote:
>>>>>    I remember Paolo saying once that we were not guarantiing any abi
>>>>> compatibility for debug mode. I haven't found any section for
>>>>> unversioned symbols in gnu.ver so I simply uncomment the global
>>>>> export.
>>>> There is no section, because all exported symbols are versioned.
>>>>
>>>> It's OK if objects compiled with Debug Mode using one version of GCC
>>>> don't link to objects compiled with Debug Mode using a different
>>>> version of GCC, but you can't change the exported symbols in the DSO.
>>>>
>>>>
>>>> Your changelog doesn't include the changes to config/abi/pre/gnu.ver,
>>>> but those changes are not OK anyway, they fail the abi-check:
>>>>
>>>> FAIL: libstdc++-abi/abi_check
>>>>
>>>>                === libstdc++ Summary ===
>>>>
>>>> # of unexpected failures        1
>>>>
>>>>
>>> Sorry, I though policy regarding debug mode symbols was even more
>>> relax.
>>> It is not so here is another patch that doesn"t break abi checks.
>>>
>>> I eventually made all methods that should not be used deprecated, they
>>> were normally not used explicitely anyway. Their implementation is now
>>> empty. I just needed to add a symbol for the not const _M_message
>>> method
>>> which is the correct signature.
>>>
>>> François
>>>
>> I eventually considered doing it without impacting exported symbols. I
>> just kept the const qualifier on _M_messages and introduced a const_cast
>> in the implementation.
>>
>> Is it ok to commit with this version ?
>
> The changes look OK now (assuming it passes 'make check-abi') but what
> does it actually do?

Mostly clean code, I have been upset in the past to be forced to
introduce new print methods to _Error_formatter or _Parameter type while
those methods were only used through a call to _M_error. Now we can
change anything to the code used to output the diagnostic without having
to also impact _Error_formatter.

I also disliked the mutable fields of _Error_formatter, it often
indicates a design flow, which was the case here.

>
> Does it significantly improve the output?

    Not significantly. I initially start working on that because debug
messages were wrapped is a bad way. The message used to be cut on any
character that was not alnum, now we cut only on space. I would like to
improve rendering of types, they are not respecting the max line length
that can be specified by users, but that's not top priority of course.

Committed.

François

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-05 21:02 debug mode symbols cleanup François Dumont
  2015-09-07 11:04 ` Jonathan Wakely
@ 2015-09-18 11:06 ` Ulrich Weigand
  2015-09-18 11:10   ` Jonathan Wakely
  1 sibling, 1 reply; 9+ messages in thread
From: Ulrich Weigand @ 2015-09-18 11:06 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

Francois Dumont wrote:

>     * include/debug/formatter.h
>     (_Error_formatter::_Parameter::_M_print_field): Delete.
>     (_Error_formatter::_Parameter::_M_print_description): Likewise.
>     (_Error_formatter::_M_format_word): Likewise.
>     (_Error_formatter::_M_print_word): Likewise.
>     (_Error_formatter::_M_print_string): Likewise.
>     (_Error_formatter::_M_get_max_length): Likewise.
>     (_Error_formatter::_M_max_length): Likewise.
>     (_Error_formatter::_M_indent): Likewise.
>     (_Error_formatter::_M_column): Likewise.
>     (_Error_formatter::_M_first_line): Likewise.
>     (_Error_formatter::_M_wordwrap): Likewise.
>     * src/c++11/debug.cc: Adapt.

This seems to break building an spu-elf cross-compiler:

/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc: In function 'void {anonymous}::print_word({anonymous}::PrintContext&, const char*, std::ptrdiff_t)':
/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc:573:10: error: 'stderr' was not declared in this scope
  fprintf(stderr, "\n");
          ^
/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc:573:22: error: 'fprintf' was not declared in this scope
  fprintf(stderr, "\n");
                      ^

Bye,
Ulrich

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-18 11:06 ` Ulrich Weigand
@ 2015-09-18 11:10   ` Jonathan Wakely
  2015-09-18 11:21     ` Ulrich Weigand
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2015-09-18 11:10 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: François Dumont, libstdc++, gcc-patches

On 18/09/15 13:00 +0200, Ulrich Weigand wrote:
>Francois Dumont wrote:
>
>>     * include/debug/formatter.h
>>     (_Error_formatter::_Parameter::_M_print_field): Delete.
>>     (_Error_formatter::_Parameter::_M_print_description): Likewise.
>>     (_Error_formatter::_M_format_word): Likewise.
>>     (_Error_formatter::_M_print_word): Likewise.
>>     (_Error_formatter::_M_print_string): Likewise.
>>     (_Error_formatter::_M_get_max_length): Likewise.
>>     (_Error_formatter::_M_max_length): Likewise.
>>     (_Error_formatter::_M_indent): Likewise.
>>     (_Error_formatter::_M_column): Likewise.
>>     (_Error_formatter::_M_first_line): Likewise.
>>     (_Error_formatter::_M_wordwrap): Likewise.
>>     * src/c++11/debug.cc: Adapt.
>
>This seems to break building an spu-elf cross-compiler:
>
>/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc: In function 'void {anonymous}::print_word({anonymous}::PrintContext&, const char*, std::ptrdiff_t)':
>/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc:573:10: error: 'stderr' was not declared in this scope
>  fprintf(stderr, "\n");
>          ^
>/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc:573:22: error: 'fprintf' was not declared in this scope
>  fprintf(stderr, "\n");
>                      ^

Catherine fixed this with r227888.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: debug mode symbols cleanup
  2015-09-18 11:10   ` Jonathan Wakely
@ 2015-09-18 11:21     ` Ulrich Weigand
  0 siblings, 0 replies; 9+ messages in thread
From: Ulrich Weigand @ 2015-09-18 11:21 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: François Dumont, libstdc++, gcc-patches

Jonathan Wakely wrote:
> On 18/09/15 13:00 +0200, Ulrich Weigand wrote:
> >/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc: In function 'void {anonymous}::print_word({anonymous}::PrintContext&, const char*, std::ptrdiff_t)':
> >/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc:573:10: error: 'stderr' was not declared in this scope
> >  fprintf(stderr, "\n");
> >          ^
> >/home/uweigand/dailybuild/spu-tc-2015-09-17/gcc-head/src/libstdc++-v3/src/c++11/debug.cc:573:22: error: 'fprintf' was not declared in this scope
> >  fprintf(stderr, "\n");
> >                      ^
> 
> Catherine fixed this with r227888.

Ah, OK.  Thanks!

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-09-18 11:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-05 21:02 debug mode symbols cleanup François Dumont
2015-09-07 11:04 ` Jonathan Wakely
2015-09-08 21:02   ` François Dumont
2015-09-14 18:27     ` François Dumont
2015-09-15 23:08       ` Jonathan Wakely
2015-09-17 19:31         ` François Dumont
2015-09-18 11:06 ` Ulrich Weigand
2015-09-18 11:10   ` Jonathan Wakely
2015-09-18 11:21     ` Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).