OSDN Git Service

* cp-demangle.c (IS_UPPER, IS_LOWER): Define.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 4 Dec 2003 19:48:44 +0000 (19:48 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 4 Dec 2003 19:48:44 +0000 (19:48 +0000)
(d_last_char): Define new macro.
(d_make_name): Reject an empty name.
(d_prefix, d_unqualified_name, d_type): Use new IS_* macros.
(d_substitution, d_print_identifier): Likewise.
(d_print_comp) [D_COMP_OPERATOR]: Likewise.
(d_print_comp) [D_COMP_TEMPLATE]: Use new d_last_char macro.
(d_print_mod) Use new d_last_char macro.
(d_print_cast): Use new d_last_char macro.
(is_ctor_or_dtor): Don't leak memory.

Fix handling of member function modifiers:
* cp-demangle.c (enum d_comp_type): Add D_COMP_RESTRICT_THIS,
D_COMP_VOLATILE_THIS, and D_COMP_CONST_THIS.
(d_dump): Dump new d_comp_type values.
(d_make_comp): Accept new d_comp_type values.
(has_return_type): Only accept _THIS variants of qualifiers.
(d_encoding): Without DMGL_PARAMS, only remove _THIS variants of
qualifiers.
(d_cv_qualifiers): Add member_fn parameter.  Change all callers.
(d_print_comp) [D_COMP_TYPED_NAME]: Rather than removing
qualifiers and printing them at the end, add _THIS qualifiers to
the modifier list.
(d_print_comp) [D_COMP_*_THIS]: New cases.
(d_print_comp) [D_COMP_PTRMEM_TYPE]: Remove special handling of
qualifiers.
(d_print_mod_list): Add suffix parameter.  Change all callers.
Keep walking the list even if the current modifier has been
printed.
(d_print_mod): Handle new _THIS qualifiers.
(d_print_function_type): Handle new _THIS qualifiers when deciding
whether to print a parenthesis.  Put a space before the
parenthesis in some cases.  Call d_print_mod_list again at the
end, passing suffix as 1.
(is_ctor_or_dtor): Look for new _THIS qualifiers.
* testsuite/demangle-expected: Add test case.

Fix for PR gcc/13304:
* cp-demangle.c (d_print_comp) [D_COMP_TEMPLATE]: If the character
before the '<' is itself a '<', insert a space.
(d_print_cast): Likewise.
* testsuite/demangle-expected: Add test case.

Fix for PR gcc/13244:
* cp-demangle.c (d_print_comp) [D_COMP_BINARY]: Wrap an expression
which uses the '>' operator in an extra layer of parens.
* testsuite/demangle-expected: Add test case.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@74290 138bc75d-0d04-0410-961f-82ee72b054a4

libiberty/ChangeLog
libiberty/cp-demangle.c
libiberty/testsuite/demangle-expected

index e3ac9a1..ef65982 100644 (file)
@@ -1,3 +1,53 @@
+2003-12-04  Ian Lance Taylor  <ian@wasabisystems.com>
+
+       * cp-demangle.c (IS_UPPER, IS_LOWER): Define.
+       (d_last_char): Define new macro.
+       (d_make_name): Reject an empty name.
+       (d_prefix, d_unqualified_name, d_type): Use new IS_* macros.
+       (d_substitution, d_print_identifier): Likewise.
+       (d_print_comp) [D_COMP_OPERATOR]: Likewise.
+       (d_print_comp) [D_COMP_TEMPLATE]: Use new d_last_char macro.
+       (d_print_mod) Use new d_last_char macro.
+       (d_print_cast): Use new d_last_char macro.
+       (is_ctor_or_dtor): Don't leak memory.
+
+       Fix handling of member function modifiers:
+       * cp-demangle.c (enum d_comp_type): Add D_COMP_RESTRICT_THIS,
+       D_COMP_VOLATILE_THIS, and D_COMP_CONST_THIS.
+       (d_dump): Dump new d_comp_type values.
+       (d_make_comp): Accept new d_comp_type values.
+       (has_return_type): Only accept _THIS variants of qualifiers.
+       (d_encoding): Without DMGL_PARAMS, only remove _THIS variants of
+       qualifiers.
+       (d_cv_qualifiers): Add member_fn parameter.  Change all callers.
+       (d_print_comp) [D_COMP_TYPED_NAME]: Rather than removing
+       qualifiers and printing them at the end, add _THIS qualifiers to
+       the modifier list.
+       (d_print_comp) [D_COMP_*_THIS]: New cases.
+       (d_print_comp) [D_COMP_PTRMEM_TYPE]: Remove special handling of
+       qualifiers.
+       (d_print_mod_list): Add suffix parameter.  Change all callers.
+       Keep walking the list even if the current modifier has been
+       printed.
+       (d_print_mod): Handle new _THIS qualifiers.
+       (d_print_function_type): Handle new _THIS qualifiers when deciding
+       whether to print a parenthesis.  Put a space before the
+       parenthesis in some cases.  Call d_print_mod_list again at the
+       end, passing suffix as 1.
+       (is_ctor_or_dtor): Look for new _THIS qualifiers.
+       * testsuite/demangle-expected: Add test case.
+
+       Fix for PR gcc/13304:
+       * cp-demangle.c (d_print_comp) [D_COMP_TEMPLATE]: If the character
+       before the '<' is itself a '<', insert a space.
+       (d_print_cast): Likewise.
+       * testsuite/demangle-expected: Add test case.
+
+       Fix for PR gcc/13244:
+       * cp-demangle.c (d_print_comp) [D_COMP_BINARY]: Wrap an expression
+       which uses the '>' operator in an extra layer of parens.
+       * testsuite/demangle-expected: Add test case.
+
 2003-12-03  Ian Lance Taylor  <ian@wasabisystems.com>
 
        * floatformat.c: Include "config.h" and <string.h> if available.
index 0fe568f..a5835df 100644 (file)
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 */
 
+/* This code implements a demangler for the g++ V3 ABI.  The ABI is
+   described on this web page:
+       http://www.codesourcery.com/cxx-abi/abi.html#mangling
+
+   This code was written while looking at the demangler written by
+   Alex Samuel <samuel@codesourcery.com>.
+
+   This code first pulls the mangled name apart into a list of
+   components, and then walks the list generating the demangled
+   name.
+
+   This file will normally define the following functions, q.v.:
+      char *cplus_demangle_v3(const char *mangled, int options)
+      char *java_demangle_v3(const char *mangled)
+      enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
+      enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
+
+   Preprocessor macros you can define while compiling this file:
+
+   IN_LIBGCC2
+      If defined, this file defines the following function, q.v.:
+         char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
+                               int *status)
+      instead of cplus_demangle_v3() and java_demangle_v3().
+
+   IN_GLIBCPP_V3
+      If defined, this file defines only __cxa_demangle().
+
+   STANDALONE_DEMANGLER
+      If defined, this file defines a main() function which demangles
+      any arguments, or, if none, demangles stdin.
+
+   CP_DEMANGLE_DEBUG
+      If defined, turns on debugging mode, which prints information on
+      stdout about the mangled string.  This is not generally useful.
+*/
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 #include "libiberty.h"
 #include "demangle.h"
 
-/* This code implements a demangler for the g++ V3 ABI.  The ABI is
-   described on this web page:
-       http://www.codesourcery.com/cxx-abi/abi.html#mangling
-
-   This code was written while looking at the demangler written by
-   Alex Samuel <samuel@codesourcery.com>.
+/* We avoid pulling in the ctype tables, to prevent pulling in
+   additional unresolved symbols when this code is used in a library.
+   FIXME: Is this really a valid reason?  This comes from the original
+   V3 demangler code.
 
-   This code first pulls the mangled name apart into a list of
-   components, and then walks the list generating the demangled
-   name.  */
+   As of this writing this file has the following undefined references
+   when compiled with -DIN_GLIBCPP_V3: malloc, realloc, free, memcpy,
+   strcpy, strcat, strlen.  */
 
-/* Avoid pulling in the ctype tables for this simple usage.  */
 #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
 
 /* The prefix prepended by GCC to an identifier represnting the
    anonymous namespace.  */
@@ -155,6 +191,12 @@ enum d_comp_type
   D_COMP_VOLATILE,
   /* The const qualifier.  */
   D_COMP_CONST,
+  /* The restrict qualifier modifying a member function.  */
+  D_COMP_RESTRICT_THIS,
+  /* The volatile qualifier modifying a member function.  */
+  D_COMP_VOLATILE_THIS,
+  /* The const qualifier modifying a member function.  */
+  D_COMP_CONST_THIS,
   /* A vendor qualifier.  */
   D_COMP_VENDOR_TYPE_QUAL,
   /* A pointer.  */
@@ -389,6 +431,9 @@ struct d_print_info
     } \
   while (0)
 
+#define d_last_char(dpi) \
+  ((dpi)->buf == NULL || (dpi)->len == 0 ? '\0' : (dpi)->buf[(dpi)->len - 1])
+
 #ifdef CP_DEMANGLE_DEBUG
 static void d_dump PARAMS ((struct d_comp *, int));
 #endif
@@ -430,7 +475,7 @@ static int d_call_offset PARAMS ((struct d_info *, int));
 static struct d_comp *d_ctor_dtor_name PARAMS ((struct d_info *));
 static struct d_comp *d_type PARAMS ((struct d_info *));
 static struct d_comp **d_cv_qualifiers PARAMS ((struct d_info *,
-                                               struct d_comp **));
+                                               struct d_comp **, int));
 static struct d_comp *d_function_type PARAMS ((struct d_info *));
 static struct d_comp *d_bare_function_type PARAMS ((struct d_info *, int));
 static struct d_comp *d_class_enum_type PARAMS ((struct d_info *));
@@ -456,7 +501,7 @@ static void d_print_comp PARAMS ((struct d_print_info *,
 static void d_print_identifier PARAMS ((struct d_print_info *, const char *,
                                        int));
 static void d_print_mod_list PARAMS ((struct d_print_info *,
-                                     struct d_print_mod *));
+                                     struct d_print_mod *, int));
 static void d_print_mod PARAMS ((struct d_print_info *,
                                 const struct d_comp *));
 static void d_print_function_type PARAMS ((struct d_print_info *,
@@ -572,6 +617,15 @@ d_dump (dc, indent)
     case D_COMP_CONST:
       printf ("const\n");
       break;
+    case D_COMP_RESTRICT_THIS:
+      printf ("restrict this\n");
+      break;
+    case D_COMP_VOLATILE_THIS:
+      printf ("volatile this\n");
+      break;
+    case D_COMP_CONST_THIS:
+      printf ("const this\n");
+      break;
     case D_COMP_VENDOR_TYPE_QUAL:
       printf ("vendor type qualifier\n");
       break;
@@ -725,6 +779,9 @@ d_make_comp (di, type, left, right)
     case D_COMP_RESTRICT:
     case D_COMP_VOLATILE:
     case D_COMP_CONST:
+    case D_COMP_RESTRICT_THIS:
+    case D_COMP_VOLATILE_THIS:
+    case D_COMP_CONST_THIS:
       break;
 
       /* Other types should not be seen here.  */
@@ -751,6 +808,8 @@ d_make_name (di, s, len)
 {
   struct d_comp *p;
 
+  if (s == NULL || len == 0)
+    return NULL;
   p = d_make_empty (di, D_COMP_NAME);
   if (p != NULL)
     {
@@ -922,10 +981,9 @@ has_return_type (dc)
       return 0;
     case D_COMP_TEMPLATE:
       return ! is_ctor_dtor_or_conversion (d_left (dc));
-    case D_COMP_RESTRICT:
-    case D_COMP_VOLATILE:
-    case D_COMP_CONST:
-    case D_COMP_VENDOR_TYPE_QUAL:
+    case D_COMP_RESTRICT_THIS:
+    case D_COMP_VOLATILE_THIS:
+    case D_COMP_CONST_THIS:
       return has_return_type (d_left (dc));
     }
 }
@@ -981,9 +1039,9 @@ d_encoding (di, top_level)
          /* Strip off any initial CV-qualifiers, as they really apply
             to the `this' parameter, and they were not output by the
             v2 demangler without DMGL_PARAMS.  */
-         while (dc->type == D_COMP_RESTRICT
-                || dc->type == D_COMP_VOLATILE
-                || dc->type == D_COMP_CONST)
+         while (dc->type == D_COMP_RESTRICT_THIS
+                || dc->type == D_COMP_VOLATILE_THIS
+                || dc->type == D_COMP_CONST_THIS)
            dc = d_left (dc);
          return dc;
        }
@@ -1092,7 +1150,7 @@ d_nested_name (di)
   if (d_next_char (di) != 'N')
     return NULL;
 
-  pret = d_cv_qualifiers (di, &ret);
+  pret = d_cv_qualifiers (di, &ret, 1);
   if (pret == NULL)
     return NULL;
 
@@ -1139,7 +1197,7 @@ d_prefix (di)
 
       comb_type = D_COMP_QUAL_NAME;
       if (IS_DIGIT (peek)
-         || (peek >= 'a' && peek <= 'z')
+         || IS_LOWER (peek)
          || peek == 'C'
          || peek == 'D')
        dc = d_unqualified_name (di);
@@ -1186,7 +1244,7 @@ d_unqualified_name (di)
   peek = d_peek_char (di);
   if (IS_DIGIT (peek))
     return d_source_name (di);
-  else if (peek >= 'a' && peek <= 'z')
+  else if (IS_LOWER (peek))
     return d_operator_name (di);
   else if (peek == 'C' || peek == 'D')
     return d_ctor_dtor_name (di);
@@ -1648,7 +1706,7 @@ d_type (di)
     {
       struct d_comp **pret;
 
-      pret = d_cv_qualifiers (di, &ret);
+      pret = d_cv_qualifiers (di, &ret, 0);
       if (pret == NULL)
        return NULL;
       *pret = d_type (di);
@@ -1716,7 +1774,7 @@ d_type (di)
        peek_next = d_peek_next_char (di);
        if (IS_DIGIT (peek_next)
            || peek_next == '_'
-           || (peek_next >= 'A' && peek_next <= 'Z'))
+           || IS_UPPER (peek_next))
          {
            ret = d_substitution (di);
            /* The substituted name may have been a template name and
@@ -1782,9 +1840,10 @@ d_type (di)
 /* <CV-qualifiers> ::= [r] [V] [K]  */
 
 static struct d_comp **
-d_cv_qualifiers (di, pret)
+d_cv_qualifiers (di, pret, member_fn)
      struct d_info *di;
      struct d_comp **pret;
+     int member_fn;
 {
   char peek;
 
@@ -1795,11 +1854,11 @@ d_cv_qualifiers (di, pret)
 
       d_advance (di, 1);
       if (peek == 'r')
-       t = D_COMP_RESTRICT;
+       t = member_fn ? D_COMP_RESTRICT_THIS: D_COMP_RESTRICT;
       else if (peek == 'V')
-       t = D_COMP_VOLATILE;
+       t = member_fn ? D_COMP_VOLATILE_THIS : D_COMP_VOLATILE;
       else
-       t = D_COMP_CONST;
+       t = member_fn ? D_COMP_CONST_THIS: D_COMP_CONST;
 
       *pret = d_make_comp (di, t, NULL, NULL);
       if (*pret == NULL)
@@ -1970,7 +2029,7 @@ d_pointer_to_member_type (di)
      with g++, we need to pull off the CV-qualifiers here, in order to
      avoid calling add_substitution() in d_type().  */
 
-  pmem = d_cv_qualifiers (di, &mem);
+  pmem = d_cv_qualifiers (di, &mem, 1);
   if (pmem == NULL)
     return NULL;
   *pmem = d_type (di);
@@ -2316,7 +2375,7 @@ d_substitution (di)
     return NULL;
 
   c = d_next_char (di);
-  if (c == '_' || IS_DIGIT (c) || (c >= 'A' && c <= 'Z'))
+  if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
     {
       int id;
 
@@ -2327,7 +2386,7 @@ d_substitution (di)
            {
              if (IS_DIGIT (c))
                id = id * 36 + c - '0';
-             else if (c >= 'A' && c <= 'Z')
+             else if (IS_UPPER (c))
                id = id * 36 + c - 'A' + 10;
              else
                return NULL;
@@ -2527,28 +2586,40 @@ d_print_comp (dpi, dc)
 
     case D_COMP_TYPED_NAME:
       {
-       const struct d_comp *typed_name;
-       struct d_print_mod dpm;
+       struct d_print_mod *hold_modifiers;
+       struct d_comp *typed_name;
+       struct d_print_mod adpm[4];
+       unsigned int i;
        struct d_print_template dpt;
 
        /* Pass the name down to the type so that it can be printed in
-          the right place for the type.  If the name has
-          CV-qualifiers, they are really method qualifiers; pull them
-          off now and print them after everything else.  Note that we
-          don't handle D_COMP_VENDOR_TYPE_QUAL here; it's not
-          accepted by d_cv_qualifiers() either.  */
+          the right place for the type.  We also have to pass down
+          any CV-qualifiers, which apply to the this parameter.  */
+       hold_modifiers = dpi->modifiers;
+       i = 0;
        typed_name = d_left (dc);
-       while (typed_name != NULL
-              && (typed_name->type == D_COMP_RESTRICT
-                  || typed_name->type == D_COMP_VOLATILE
-                  || typed_name->type == D_COMP_CONST))
-         typed_name = d_left (typed_name);
+       while (typed_name != NULL)
+         {
+           if (i >= sizeof adpm / sizeof adpm[0])
+             {
+               d_print_error (dpi);
+               return;
+             }
 
-       dpm.next = dpi->modifiers;
-       dpi->modifiers = &dpm;
-       dpm.mod = typed_name;
-       dpm.printed = 0;
-       dpm.templates = dpi->templates;
+           adpm[i].next = dpi->modifiers;
+           dpi->modifiers = &adpm[i];
+           adpm[i].mod = typed_name;
+           adpm[i].printed = 0;
+           adpm[i].templates = dpi->templates;
+           ++i;
+
+           if (typed_name->type != D_COMP_RESTRICT_THIS
+               && typed_name->type != D_COMP_VOLATILE_THIS
+               && typed_name->type != D_COMP_CONST_THIS)
+             break;
+
+           typed_name = d_left (typed_name);
+         }
 
        /* If typed_name is a template, then it applies to the
           function type as well.  */
@@ -2564,26 +2635,19 @@ d_print_comp (dpi, dc)
        if (typed_name->type == D_COMP_TEMPLATE)
          dpi->templates = dpt.next;
 
-       /* If the modifier didn't get printed by the type, print it
+       /* If the modifiers didn't get printed by the type, print them
           now.  */
-       if (! dpm.printed)
+       while (i > 0)
          {
-           d_append_char (dpi, ' ');
-           d_print_comp (dpi, typed_name);
+           --i;
+           if (! adpm[i].printed)
+             {
+               d_append_char (dpi, ' ');
+               d_print_mod (dpi, adpm[i].mod);
+             }
          }
 
-       dpi->modifiers = dpm.next;
-
-       /* Now print any CV-qualifiers on the type.  */
-       typed_name = d_left (dc);
-       while (typed_name != NULL
-              && (typed_name->type == D_COMP_RESTRICT
-                  || typed_name->type == D_COMP_VOLATILE
-                  || typed_name->type == D_COMP_CONST))
-         {
-           d_print_mod (dpi, typed_name);
-           typed_name = d_left (typed_name);
-         }
+       dpi->modifiers = hold_modifiers;
 
        return;
       }
@@ -2600,11 +2664,13 @@ d_print_comp (dpi, dc)
        dpi->modifiers = NULL;
 
        d_print_comp (dpi, d_left (dc));
+       if (d_last_char (dpi) == '<')
+         d_append_char (dpi, ' ');
        d_append_char (dpi, '<');
        d_print_comp (dpi, d_right (dc));
        /* Avoid generating two consecutive '>' characters, to avoid
           the C++ syntactic ambiguity.  */
-       if (dpi->buf != NULL && dpi->buf[dpi->len - 1] == '>')
+       if (d_last_char (dpi) == '>')
          d_append_char (dpi, ' ');
        d_append_char (dpi, '>');
 
@@ -2737,6 +2803,9 @@ d_print_comp (dpi, dc)
     case D_COMP_RESTRICT:
     case D_COMP_VOLATILE:
     case D_COMP_CONST:
+    case D_COMP_RESTRICT_THIS:
+    case D_COMP_VOLATILE_THIS:
+    case D_COMP_CONST_THIS:
     case D_COMP_VENDOR_TYPE_QUAL:
     case D_COMP_POINTER:
     case D_COMP_REFERENCE:
@@ -2832,27 +2901,15 @@ d_print_comp (dpi, dc)
 
     case D_COMP_PTRMEM_TYPE:
       {
-       const struct d_comp *target_type;
        struct d_print_mod dpm;
 
-       /* Pass the name down to the type so that it can be printed in
-          the right place for the type.  If the type has
-          CV-qualifiers, they are really method qualifiers; pull them
-          off now and print them after everything else.  */
-       target_type = d_right (dc);
-       while (target_type != NULL
-              && (target_type->type == D_COMP_RESTRICT
-                  || target_type->type == D_COMP_VOLATILE
-                  || target_type->type == D_COMP_CONST))
-         target_type = d_left (target_type);
-
        dpm.next = dpi->modifiers;
        dpi->modifiers = &dpm;
        dpm.mod = dc;
        dpm.printed = 0;
        dpm.templates = dpi->templates;
 
-       d_print_comp (dpi, target_type);
+       d_print_comp (dpi, d_right (dc));
 
        /* If the modifier didn't get printed by the type, print it
           now.  */
@@ -2865,17 +2922,6 @@ d_print_comp (dpi, dc)
 
        dpi->modifiers = dpm.next;
 
-       /* Now print any CV-qualifiers on the type.  */
-       target_type = d_right (dc);
-       while (target_type != NULL
-              && (target_type->type == D_COMP_RESTRICT
-                  || target_type->type == D_COMP_VOLATILE
-                  || target_type->type == D_COMP_CONST))
-         {
-           d_print_mod (dpi, target_type);
-           target_type = d_left (target_type);
-         }
-
        return;
       }
 
@@ -2895,7 +2941,7 @@ d_print_comp (dpi, dc)
 
        d_append_string (dpi, "operator");
        c = dc->u.s_operator.op->name[0];
-       if (c >= 'a' && c <= 'z')
+       if (IS_LOWER (c))
          d_append_char (dpi, ' ');
        d_append_string (dpi, dc->u.s_operator.op->name);
        return;
@@ -2933,6 +2979,14 @@ d_print_comp (dpi, dc)
          d_print_error (dpi);
          return;
        }
+
+      /* We wrap an expression which uses the greater-than operator in
+        an extra layer of parens so that it does not get confused
+        with the '>' which ends the template parameters.  */
+      if (d_left (dc)->type == D_COMP_OPERATOR
+         && strcmp (d_left (dc)->u.s_operator.op->name, ">") == 0)
+       d_append_char (dpi, '(');
+
       d_append_char (dpi, '(');
       d_print_comp (dpi, d_left (d_right (dc)));
       d_append_string (dpi, ") ");
@@ -2940,6 +2994,11 @@ d_print_comp (dpi, dc)
       d_append_string (dpi, " (");
       d_print_comp (dpi, d_right (d_right (dc)));
       d_append_char (dpi, ')');
+
+      if (d_left (dc)->type == D_COMP_OPERATOR
+         && strcmp (d_left (dc)->u.s_operator.op->name, ">") == 0)
+       d_append_char (dpi, ')');
+
       return;
 
     case D_COMP_BINARY_ARGS:
@@ -3064,7 +3123,7 @@ d_print_identifier (dpi, name, len)
                {
                  int dig;
 
-                 if (*q >= '0' && *q <= '9')
+                 if (IS_DIGIT (*q))
                    dig = *q - '0';
                  else if (*q >= 'A' && *q <= 'F')
                    dig = *q - 'A' + 10;
@@ -3090,18 +3149,30 @@ d_print_identifier (dpi, name, len)
     }
 }
 
-/* Print a list of modifiers.  */
+/* Print a list of modifiers.  SUFFIX is 1 if we are printing
+   qualifiers on this after printing a function.  */
 
 static void
-d_print_mod_list (dpi, mods)
+d_print_mod_list (dpi, mods, suffix)
      struct d_print_info *dpi;
      struct d_print_mod *mods;
+     int suffix;
 {
   struct d_print_template *hold_dpt;
 
-  if (mods == NULL || mods->printed || d_print_saw_error (dpi))
+  if (mods == NULL || d_print_saw_error (dpi))
     return;
 
+  if (mods->printed
+      || (! suffix
+         && (mods->mod->type == D_COMP_RESTRICT_THIS
+             || mods->mod->type == D_COMP_VOLATILE_THIS
+             || mods->mod->type == D_COMP_CONST_THIS)))
+    {
+      d_print_mod_list (dpi, mods->next, suffix);
+      return;
+    }
+
   mods->printed = 1;
 
   hold_dpt = dpi->templates;
@@ -3124,7 +3195,7 @@ d_print_mod_list (dpi, mods)
 
   dpi->templates = hold_dpt;
 
-  d_print_mod_list (dpi, mods->next);
+  d_print_mod_list (dpi, mods->next, suffix);
 }
 
 /* Print a modifier.  */
@@ -3137,12 +3208,15 @@ d_print_mod (dpi, mod)
   switch (mod->type)
     {
     case D_COMP_RESTRICT:
+    case D_COMP_RESTRICT_THIS:
       d_append_string (dpi, " restrict");
       return;
     case D_COMP_VOLATILE:
+    case D_COMP_VOLATILE_THIS:
       d_append_string (dpi, " volatile");
       return;
     case D_COMP_CONST:
+    case D_COMP_CONST_THIS:
       d_append_string (dpi, " const");
       return;
     case D_COMP_VENDOR_TYPE_QUAL:
@@ -3164,7 +3238,7 @@ d_print_mod (dpi, mod)
       d_append_string (dpi, "imaginary ");
       return;
     case D_COMP_PTRMEM_TYPE:
-      if (dpi->buf != NULL && dpi->buf[dpi->len - 1] != '(')
+      if (d_last_char (dpi) != '(')
        d_append_char (dpi, ' ');
       d_print_comp (dpi, d_left (mod));
       d_append_string (dpi, "::*");
@@ -3213,6 +3287,10 @@ d_print_function_type (dpi, dc, mods)
        case D_COMP_PTRMEM_TYPE:
          need_paren = 1;
          break;
+       case D_COMP_RESTRICT_THIS:
+       case D_COMP_VOLATILE_THIS:
+       case D_COMP_CONST_THIS:
+         break;
        default:
          break;
        }
@@ -3224,9 +3302,23 @@ d_print_function_type (dpi, dc, mods)
     need_paren = 1;
 
   if (need_paren)
-    d_append_char (dpi, '(');
+    {
+      switch (d_last_char (dpi))
+       {
+       case ' ':
+       case '(':
+       case '*':
+         break;
 
-  d_print_mod_list (dpi, mods);
+       default:
+         d_append_char (dpi, ' ');
+         break;
+       }
+
+      d_append_char (dpi, '(');
+    }
+
+  d_print_mod_list (dpi, mods, 0);
 
   if (need_paren)
     d_append_char (dpi, ')');
@@ -3237,6 +3329,8 @@ d_print_function_type (dpi, dc, mods)
     d_print_comp (dpi, d_right (dc));
 
   d_append_char (dpi, ')');
+
+  d_print_mod_list (dpi, mods, 1);
 }
 
 /* Print an array type, except for the element type.  */
@@ -3277,7 +3371,7 @@ d_print_array_type (dpi, dc, mods)
       if (need_paren)
        d_append_string (dpi, " (");
 
-      d_print_mod_list (dpi, mods);
+      d_print_mod_list (dpi, mods, 0);
 
       if (need_paren)
        d_append_char (dpi, ')');
@@ -3337,11 +3431,13 @@ d_print_cast (dpi, dc)
 
       dpi->templates = dpt.next;
 
+      if (d_last_char (dpi) == '<')
+       d_append_char (dpi, ' ');
       d_append_char (dpi, '<');
       d_print_comp (dpi, d_right (d_left (dc)));
       /* Avoid generating two consecutive '>' characters, to avoid
         the C++ syntactic ambiguity.  */
-      if (dpi->buf != NULL && dpi->buf[dpi->len - 1] == '>')
+      if (d_last_char (dpi) == '>')
        d_append_char (dpi, ' ');
       d_append_char (dpi, '>');
 
@@ -3653,6 +3749,7 @@ is_ctor_or_dtor (mangled, ctor_kind, dtor_kind)
 {
   struct d_info di;
   struct d_comp *dc;
+  int ret;
 
   *ctor_kind = (enum gnu_v3_ctor_kinds) 0;
   *dtor_kind = (enum gnu_v3_dtor_kinds) 0;
@@ -3662,36 +3759,44 @@ is_ctor_or_dtor (mangled, ctor_kind, dtor_kind)
 
   dc = d_mangled_name (&di, 1);
 
-  if (dc == NULL || d_peek_char (&di) != '\0')
-    return 0;
-
-  while (dc != NULL)
+  ret = 0;
+  if (d_peek_char (&di) == '\0')
     {
-      switch (dc->type)
+      while (dc != NULL)
        {
-       default:
-         return 0;
-       case D_COMP_TYPED_NAME:
-       case D_COMP_TEMPLATE:
-       case D_COMP_RESTRICT:
-       case D_COMP_VOLATILE:
-       case D_COMP_CONST:
-       case D_COMP_VENDOR_TYPE_QUAL:
-         dc = d_left (dc);
-         break;
-       case D_COMP_QUAL_NAME:
-         dc = d_right (dc);
-         break;
-       case D_COMP_CTOR:
-         *ctor_kind = dc->u.s_ctor.kind;
-         return 1;
-       case D_COMP_DTOR:
-         *dtor_kind = dc->u.s_dtor.kind;
-         return 1;
+         switch (dc->type)
+           {
+           default:
+             dc = NULL;
+             break;
+           case D_COMP_TYPED_NAME:
+           case D_COMP_TEMPLATE:
+           case D_COMP_RESTRICT_THIS:
+           case D_COMP_VOLATILE_THIS:
+           case D_COMP_CONST_THIS:
+             dc = d_left (dc);
+             break;
+           case D_COMP_QUAL_NAME:
+             dc = d_right (dc);
+             break;
+           case D_COMP_CTOR:
+             *ctor_kind = dc->u.s_ctor.kind;
+             ret = 1;
+             dc = NULL;
+             break;
+           case D_COMP_DTOR:
+             *dtor_kind = dc->u.s_dtor.kind;
+             ret = 1;
+             dc = NULL;
+             break;
+           }
        }
     }
 
-  return 0;
+  free (di.subs);
+  free (di.comps);
+
+  return ret;
 }
 
 /* Return whether NAME is the mangled form of a g++ V3 ABI constructor
index bb90aa0..c47c6ae 100644 (file)
@@ -2883,10 +2883,28 @@ void __gnu_debug::_Error_formatter::_M_format_word<unsigned long>(char*, int, ch
 --format=gnu-v3
 _ZSt18uninitialized_copyIN9__gnu_cxx17__normal_iteratorIPSt4pairISsPFbP6sqlitePPcEESt6vectorIS9_SaIS9_EEEESE_ET0_T_SG_SF_
 __gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > > std::uninitialized_copy<__gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > >, __gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > > >(__gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > >, __gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > >, __gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > >)
+#
 # The new demangler used to fail on this.
 --format=gnu-v3
 _Z1fP1cIPFiiEE
 f(c<int (*)(int)>*)
+#
+# Wrap expressions using '>' in an extra layer of parens to avoid
+# confusion with the '>' which ends the template parameters.
+--format=gnu-v3
+_Z4dep9ILi3EEvP3fooIXgtT_Li2EEE
+void dep9<3>(foo<((3) > (2))>*)
+#
+# Watch out for templated version of `operator<'--it needs an extra
+# space.
+--format=gnu-v3
+_ZStltI9file_pathSsEbRKSt4pairIT_T0_ES6_
+bool std::operator< <file_path, std::string>(std::pair<file_path, std::string> const&, std::pair<file_path, std::string> const&)
+#
+# More hairy qualifier handling.
+--format=gnu-v3
+_Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE
+hairyfunc(int (* const (X::** (* restrict (* volatile*(Y::*)(int) const)(char*)) [2])(long) const) [3])
 # 
 # This caused an infinite loop.
 #