]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cplus-dem.c: Incorporate changes from GCC version not present in the libiberty version.
authorMark Mitchell <mark@markmitchell.com>
Mon, 13 Jul 1998 10:54:01 +0000 (10:54 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 13 Jul 1998 10:54:01 +0000 (10:54 +0000)
* cplus-dem.c: Incorporate changes from GCC version not present in
the libiberty version.

From-SVN: r21101

libiberty/ChangeLog
libiberty/cplus-dem.c

index e6a6e45f16dcef084ff510768cfdcd983184d990..3695690f3f75869815580281aa8efcab7b54e581 100644 (file)
@@ -1,3 +1,8 @@
+1998-07-13  Mark Mitchell  <mark@markmitchell.com>
+
+       * cplus-dem.c: Incorporate changes from GCC version not present in
+       the libiberty version.
+
 Sat May 30 22:17:13 1998  Mumit Khan  <khan@xraylith.wisc.edu>
 
        * configure.in (checkfuncs): Add missing "'".
index f1ac763984af8fc6655518a5386eb4df999fd661..c754734f0776c6df02e86684620a3c642823388f 100644 (file)
@@ -1,5 +1,5 @@
 /* Demangler for GNU C++ 
-   Copyright 1989, 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    Written by James Clark (jjc@jclark.uucp)
    Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
    
@@ -94,6 +94,13 @@ set_cplus_marker_for_demangling (ch)
   cplus_markers[0] = ch;
 }
 
+typedef struct string          /* Beware: these aren't required to be */
+{                              /*  '\0' terminated.  */
+  char *b;                     /* pointer to start of string */
+  char *p;                     /* pointer after last character */
+  char *e;                     /* pointer after end of allocated space */
+} string;
+
 /* Stuff that is shared between sub-routines.
    Using a shared structure allows cplus_demangle to be reentrant.  */
 
@@ -113,8 +120,14 @@ struct work_stuff
   int destructor;
   int static_type;     /* A static member function */
   int const_type;      /* A const member function */
+  int volatile_type;    /* A volatile member function */
   char **tmpl_argvec;   /* Template function arguments. */
   int ntmpl_args;       /* The number of template function arguments. */
+  int forgetting_types; /* Nonzero if we are not remembering the types
+                          we see.  */
+  string* previous_argument; /* The last function argument demangled.  */
+  int nrepeats;         /* The number of times to repeat the previous
+                          argument.  */
 };
 
 #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -208,13 +221,6 @@ static const struct optable
 };
 
 
-typedef struct string          /* Beware: these aren't required to be */
-{                              /*  '\0' terminated.  */
-  char *b;                     /* pointer to start of string */
-  char *p;                     /* pointer after last character */
-  char *e;                     /* pointer after end of allocated space */
-} string;
-
 #define STRING_EMPTY(str)      ((str) -> b == (str) -> p)
 #define PREPEND_BLANK(str)     {if (!STRING_EMPTY(str)) \
     string_prepend(str, " ");}
@@ -222,6 +228,9 @@ typedef struct string               /* Beware: these aren't required to be */
     string_append(str, " ");}
 #define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
 
+/* The scope separator appropriate for the language being demangled.  */
+#define SCOPE_STRING(work) "::"
+
 #define ARM_VTABLE_STRING "__vtbl__"   /* Lucid/ARM virtual table prefix */
 #define ARM_VTABLE_STRLEN 8            /* strlen (ARM_VTABLE_STRING) */
 
@@ -247,7 +256,7 @@ demangle_template_template_parm PARAMS ((struct work_stuff *work,
 
 static int
 demangle_template PARAMS ((struct work_stuff *work, const char **, string *,
-                          string *, int));
+                          string *, int, int));
 
 static int
 arm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
@@ -325,6 +334,9 @@ consume_count_with_underscores PARAMS ((const char**));
 static int
 demangle_args PARAMS ((struct work_stuff *, const char **, string *));
 
+static int
+demangle_nested_args PARAMS ((struct work_stuff*, const char**, string*));
+
 static int
 do_type PARAMS ((struct work_stuff *, const char **, string *));
 
@@ -632,12 +644,15 @@ internal_cplus_demangle (work, mangled)
   int success = 0;
   char *demangled = NULL;
   int s1,s2,s3,s4;
+  int saved_volatile_type;
   s1 = work->constructor;
   s2 = work->destructor;
   s3 = work->static_type;
   s4 = work->const_type;
+  saved_volatile_type = work->volatile_type;
   work->constructor = work->destructor = 0;
   work->static_type = work->const_type = 0;
+  work->volatile_type = 0;
 
   if ((mangled != NULL) && (*mangled != '\0'))
     {
@@ -678,6 +693,7 @@ internal_cplus_demangle (work, mangled)
   work->destructor = s2;
   work->static_type = s3;
   work->const_type = s4;
+  work->volatile_type = saved_volatile_type;
   return (demangled);
 }
 
@@ -728,6 +744,11 @@ mop_up (work, declp, success)
       free ((char*) work->tmpl_argvec);
       work->tmpl_argvec = NULL;
     }
+  if (work->previous_argument)
+    {
+      string_delete (work->previous_argument);
+      free ((char*) work->previous_argument);
+    }
 
   /* If demangling was successful, ensure that the demangled string is null
      terminated and return it.  Otherwise, free the demangling decl.  */
@@ -796,13 +817,9 @@ demangle_signature (work, mangled, declp)
          oldmangled = *mangled;
          success = demangle_qualified (work, mangled, declp, 1, 0);
          if (success)
-           {
-             remember_type (work, oldmangled, *mangled - oldmangled);
-           }
+           remember_type (work, oldmangled, *mangled - oldmangled);
          if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             expect_func = 1;
-           }
+           expect_func = 1;
          oldmangled = NULL;
          break;
 
@@ -827,13 +844,16 @@ demangle_signature (work, mangled, declp)
          break;
 
        case 'C':
-         /* a const member function */
+       case 'V':
+         if (**mangled == 'C')
+           work -> const_type = 1;
+         else
+           work->volatile_type = 1;
+
+         /* a qualified member function */
          if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
+           oldmangled = *mangled;
          (*mangled)++;
-         work -> const_type = 1;
          break;
          
        case '0': case '1': case '2': case '3': case '4':
@@ -853,7 +873,21 @@ demangle_signature (work, mangled, declp)
            }
          oldmangled = NULL;
          break;
-         
+
+       case 'B':
+         {
+           string s;
+           success = do_type (work, mangled, &s);
+           if (success)
+             {
+               string_append (&s, SCOPE_STRING (work));
+               string_prepends (declp, &s);
+             }
+           oldmangled = NULL;
+           expect_func = 1;
+         }
+         break;
+
        case 'F':
          /* Function */
          /* ARM style demangling includes a specific 'F' character after
@@ -885,13 +919,13 @@ demangle_signature (work, mangled, declp)
            {
              oldmangled = *mangled;
            }
-         success = demangle_template (work, mangled, &tname, &trawname, 1);
+         success = demangle_template (work, mangled, &tname,
+                                      &trawname, 1, 1);
          if (success)
            {
              remember_type (work, oldmangled, *mangled - oldmangled);
            }
-           string_append (&tname, "::");
-
+         string_append(&tname, SCOPE_STRING (work));
          string_prepends(declp, &tname);
          if (work -> destructor & 1)
            {
@@ -938,7 +972,8 @@ demangle_signature (work, mangled, declp)
          if (GNU_DEMANGLING) 
            {
              /* A G++ template function.  Read the template arguments. */
-             success = demangle_template (work, mangled, declp, 0, 0);
+             success = demangle_template (work, mangled, declp, 0, 0,
+                                          0);
              if (!(work->constructor & 1))
                expect_return_type = 1;
              (*mangled)++;
@@ -995,13 +1030,12 @@ demangle_signature (work, mangled, declp)
        }
     }
   if (success && work -> static_type && PRINT_ARG_TYPES)
-    {
-      string_append (declp, " static");
-    }
+    string_append (declp, " static");
   if (success && work -> const_type && PRINT_ARG_TYPES)
-    {
-      string_append (declp, " const");
-    }
+    string_append (declp, " const");
+  else if (success && work->volatile_type && PRINT_ARG_TYPES)
+    string_append (declp, " volatile");
+
   return (success);
 }
 
@@ -1213,12 +1247,10 @@ demangle_template_value_parm (work, mangled, s)
          continue;
        case 'E':       /* expression */
        case 'Q':       /* qualified name */
-       case 'K':       /* qualified name */
-         done = is_integral = 1;
-         break;
-       case 'B':       /* squangled name */
+       case 'K':       /* qualified name */
          done = is_integral = 1;
          break;
+       case 'B':       /* remembered type */
        case 'T':       /* remembered type */
          abort ();
          break;
@@ -1362,13 +1394,22 @@ demangle_template_value_parm (work, mangled, s)
   return success;
 }
 
+/* Demangle the template name in MANGLED.  The full name of the
+   template (e.g., S<int>) is placed in TNAME.  The name without the
+   template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
+   non-NULL.  If IS_TYPE is nonzero, this template is a type template,
+   not a function template.  If both IS_TYPE and REMEMBER are nonzero,
+   the tmeplate is remembered in the list of back-referenceable
+   types.  */
+
 static int
-demangle_template (work, mangled, tname, trawname, is_type)
+demangle_template (work, mangled, tname, trawname, is_type, remember)
      struct work_stuff *work;
      const char **mangled;
      string *tname;
      string *trawname;
      int is_type;
+     int remember;
 {
   int i;
   int r;
@@ -1376,10 +1417,13 @@ demangle_template (work, mangled, tname, trawname, is_type)
   int success = 0;
   const char *start;
   string temp;
+  int bindex;
 
   (*mangled)++;
   if (is_type)
     {
+      if (remember)
+       bindex = register_Btype (work);
       start = *mangled;
       /* get template name */
       if (**mangled == 'z')
@@ -1392,9 +1436,8 @@ demangle_template (work, mangled, tname, trawname, is_type)
          if (idx == -1 
              || (work->tmpl_argvec && idx >= work->ntmpl_args)
              || consume_count_with_underscores (mangled) == -1)
-           {
-             return (0);
-           }
+           return (0);
+
          if (work->tmpl_argvec)
            {
              string_append (tname, work->tmpl_argvec[idx]);
@@ -1407,7 +1450,7 @@ demangle_template (work, mangled, tname, trawname, is_type)
              sprintf(buf, "T%d", idx);
              string_append (tname, buf);
              if (trawname)
-               string_append (trawname, work->tmpl_argvec[idx]);
+               string_append (trawname, buf);
            }
        }
       else
@@ -1416,13 +1459,13 @@ demangle_template (work, mangled, tname, trawname, is_type)
            {
              return (0);
            }
+         string_appendn (tname, *mangled, r);
          if (trawname)
            string_appendn (trawname, *mangled, r);
-             string_appendn (tname, *mangled, r);
          *mangled += r;
        }
     }
-    string_append (tname, "<");
+  string_append (tname, "<");
   /* get size of template parameter list */
   if (!get_count (mangled, &r))
     {
@@ -1549,12 +1592,13 @@ demangle_template (work, mangled, tname, trawname, is_type)
        }
       need_comma = 1;
     }
-    {
-      if (tname->p[-1] == '>')
-       string_append (tname, " ");
-      string_append (tname, ">");
-    }
+  if (tname->p[-1] == '>')
+    string_append (tname, " ");
+  string_append (tname, ">");
   
+  if (is_type && remember)
+    remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
+
   /*
     if (work -> static_type)
     {
@@ -1712,7 +1756,7 @@ demangle_class (work, mangled, declp)
        }
       remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
       remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
-       string_prepend (declp, "::");
+      string_prepend (declp, SCOPE_STRING (work));
       string_prepends (declp, &class_name);
       success = 1;
     }
@@ -1986,7 +2030,8 @@ gnu_special (work, mangled, declp)
              success = demangle_qualified (work, mangled, declp, 0, 1);
              break;
            case 't':
-             success = demangle_template (work, mangled, declp, 0, 1);
+             success = demangle_template (work, mangled, declp, 0, 1,
+                                          1);
              break;
            default:
              if (isdigit(*mangled[0]))
@@ -2014,7 +2059,7 @@ gnu_special (work, mangled, declp)
            {
              if (p != NULL)
                {
-                   string_append (declp, "::");
+                 string_append (declp, SCOPE_STRING (work));
                  (*mangled)++;
                }
            }
@@ -2040,7 +2085,7 @@ gnu_special (work, mangled, declp)
          success = demangle_qualified (work, mangled, declp, 0, 1);
          break;
        case 't':
-         success = demangle_template (work, mangled, declp, 0, 1);
+         success = demangle_template (work, mangled, declp, 0, 1, 1);
          break;
        default:
          n = consume_count (mangled);
@@ -2052,7 +2097,7 @@ gnu_special (work, mangled, declp)
          /* Consumed everything up to the cplus_marker, append the
             variable name.  */
          (*mangled)++;
-           string_append (declp, "::");
+         string_append (declp, SCOPE_STRING (work));
          n = strlen (*mangled);
          string_appendn (declp, *mangled, n);
          (*mangled) += n;
@@ -2093,7 +2138,7 @@ gnu_special (work, mangled, declp)
          success = demangle_qualified (work, mangled, declp, 0, 1);
          break;
        case 't':
-         success = demangle_template (work, mangled, declp, 0, 1);
+         success = demangle_template (work, mangled, declp, 0, 1, 1);
          break;
        default:
          success = demangle_fund_type (work, mangled, declp);
@@ -2225,13 +2270,20 @@ demangle_qualified (work, mangled, result, isfuncname, append)
      int append;
 {
   int qualifiers = 0;
-  int namelength;
   int success = 1;
   const char *p;
   char num[2];
   string temp;
+  string last_name;
+  int bindex = register_Btype (work);
+
+  /* We only make use of ISFUNCNAME if the entity is a constructor or
+     destructor.  */
+  isfuncname = (isfuncname 
+               && ((work->constructor & 1) || (work->destructor & 1)));
 
   string_init (&temp);
+  string_init (&last_name);
 
   if ((*mangled)[0] == 'K')
     {
@@ -2304,18 +2356,24 @@ demangle_qualified (work, mangled, result, isfuncname, append)
   while (qualifiers-- > 0)
     {
       int remember_K = 1;
+      string_clear (&last_name);
+
       if (*mangled[0] == '_') 
-       *mangled = *mangled + 1;
+       (*mangled)++;
+
       if (*mangled[0] == 't')
        {
-         success = demangle_template(work, mangled, &temp, 0, 1);
-         if (!success) break;
-       }
-      else if (*mangled[0] == 'X')
-       {
-         success = do_type (work, mangled, &temp);
-         if (!success) break;
-       }
+         /* Here we always append to TEMP since we will want to use
+            the template name without the template parameters as a
+            constructor or destructor name.  The appropriate
+            (parameter-less) value is returned by demangle_template
+            in LAST_NAME.  We do not remember the template type here,
+            in order to match the G++ mangling algorithm.  */
+         success = demangle_template(work, mangled, &temp, 
+                                     &last_name, 1, 0);
+         if (!success) 
+           break;
+       } 
       else if (*mangled[0] == 'K')
        {
           int idx;
@@ -2330,60 +2388,48 @@ demangle_qualified (work, mangled, result, isfuncname, append)
          if (!success) break;
        }
       else
-        {      
-         namelength = consume_count (mangled);
-         if (strlen (*mangled) < namelength)
-           {
-             /* Simple sanity check failed */
-             success = 0;
-             break;
-           }
-         string_appendn (&temp, *mangled, namelength);
-         *mangled += namelength;
+       {
+         success = do_type (work, mangled, &last_name);
+         if (!success)
+           break;
+         string_appends (&temp, &last_name);
        }
 
       if (remember_K)
-        {
-        remember_Ktype (work, temp.b, LEN_STRING (&temp));
-        }
+       remember_Ktype (work, temp.b, LEN_STRING (&temp));
 
       if (qualifiers > 0)
-        {
-           string_append (&temp, "::");
-        }
+       string_append (&temp, SCOPE_STRING (work));
     }
 
+  remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
+
   /* If we are using the result as a function name, we need to append
      the appropriate '::' separated constructor or destructor name.
      We do this here because this is the most convenient place, where
      we already have a pointer to the name and the length of the name.  */
 
-  if (isfuncname && (work->constructor & 1 || work->destructor & 1))
+  if (isfuncname
     {
-       string_append (&temp, "::");
+      string_append (&temp, SCOPE_STRING (work));
       if (work -> destructor & 1)
-       {
-         string_append (&temp, "~");
-       }
-      string_appendn (&temp, (*mangled) - namelength, namelength);
+       string_append (&temp, "~");
+      string_appends (&temp, &last_name);
     }
 
   /* Now either prepend the temp buffer to the result, or append it, 
      depending upon the state of the append flag.  */
 
   if (append)
-    {
-      string_appends (result, &temp);
-    }
+    string_appends (result, &temp);
   else
     {
       if (!STRING_EMPTY (result))
-       {
-           string_append (&temp, "::");
-       }
+       string_append (&temp, SCOPE_STRING (work));
       string_prepends (result, &temp);
     }
 
+  string_delete (&last_name);
   string_delete (&temp);
   return (success);
 }
@@ -2474,7 +2520,7 @@ do_type (work, mangled, result)
        case 'P':
        case 'p':
          (*mangled)++;
-           string_prepend (&decl, "*");
+         string_prepend (&decl, "*");
          break;
 
          /* A reference type */
@@ -2530,15 +2576,14 @@ do_type (work, mangled, result)
          /* After picking off the function args, we expect to either find the
             function return type (preceded by an '_') or the end of the
             string.  */
-         if (!demangle_args (work, mangled, &decl)
+         if (!demangle_nested_args (work, mangled, &decl)
              || (**mangled != '_' && **mangled != '\0'))
            {
              success = 0;
+             break;
            }
          if (success && (**mangled == '_'))
-           {
-             (*mangled)++;
-           }
+           (*mangled)++;
          break;
 
        case 'M':
@@ -2556,7 +2601,7 @@ do_type (work, mangled, result)
              }
 
            string_append (&decl, ")");
-             string_prepend (&decl, "::");
+           string_prepend (&decl, SCOPE_STRING (work));
            if (isdigit (**mangled)) 
              {
                n = consume_count (mangled);
@@ -2572,7 +2617,8 @@ do_type (work, mangled, result)
              {
                string temp;
                string_init (&temp);
-               success = demangle_template (work, mangled, &temp, NULL, 1);
+               success = demangle_template (work, mangled, &temp,
+                                            NULL, 1, 1);
                if (success)
                  {
                    string_prependn (&decl, temp.b, temp.p - temp.b);
@@ -2600,7 +2646,7 @@ do_type (work, mangled, result)
                    break;
                  }
              }
-           if ((member && !demangle_args (work, mangled, &decl))
+           if ((member && !demangle_nested_args (work, mangled, &decl))
                || **mangled != '_')
              {
                success = 0;
@@ -2661,10 +2707,7 @@ do_type (work, mangled, result)
     case 'Q':
     case 'K':
       {
-        int btype = register_Btype (work);
         success = demangle_qualified (work, mangled, result, 0, 1);
-        remember_Btype (work, result->b, LEN_STRING (result), btype);
-
         break;
       }
 
@@ -2894,9 +2937,7 @@ demangle_fund_type (work, mangled, result)
       }
     case 't':
       {
-        int bindex= register_Btype (work);
-        success = demangle_template (work, mangled, &btype, 0, 1);
-        remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
+        success = demangle_template (work, mangled, &btype, 0, 1, 1);
         string_appends (result, &btype);
         break;
       }
@@ -2908,7 +2949,9 @@ demangle_fund_type (work, mangled, result)
   return (success);
 }
 
-/* `result' will be initialized in do_type; it will be freed on failure */
+/* Demangle the next argument, given by MANGLED into RESULT, which
+   *should be an uninitialized* string.  It will be initialized here,
+   and free'd should anything go wrong.  */
 
 static int
 do_arg (work, mangled, result)
@@ -2916,17 +2959,67 @@ do_arg (work, mangled, result)
      const char **mangled;
      string *result;
 {
+  /* Remember where we started so that we can record the type, for
+     non-squangling type remembering.  */
   const char *start = *mangled;
 
-  if (!do_type (work, mangled, result))
+  string_init (result);
+
+  if (work->nrepeats > 0)
     {
-      return (0);
+      --work->nrepeats;
+
+      if (work->previous_argument == 0)
+       return 0;
+
+      /* We want to reissue the previous type in this argument list.  */ 
+      string_appends (result, work->previous_argument);
+      return 1;
+    }
+
+  if (**mangled == 'n')
+    {
+      /* A squangling-style repeat.  */
+      (*mangled)++;
+      work->nrepeats = consume_count(mangled);
+
+      if (work->nrepeats == 0)
+       /* This was not a repeat count after all.  */
+       return 0;
+
+      if (work->nrepeats > 9)
+       {
+         if (**mangled != '_')
+           /* The repeat count should be followed by an '_' in this
+              case.  */
+           return 0;
+         else
+           (*mangled)++;
+       }
+      
+      /* Now, the repeat is all set up.  */
+      return do_arg (work, mangled, result);
     }
+
+  /* Save the result in WORK->previous_argument so that we can find it
+     if it's repeated.  Note that saving START is not good enough: we
+     do not want to add additional types to the back-referenceable
+     type vector when processing a repeated type.  */
+  if (work->previous_argument)
+    string_clear (work->previous_argument);
   else
     {
-      remember_type (work, start, *mangled - start);
-      return (1);
+      work->previous_argument = (string*) xmalloc (sizeof (string));
+      string_init (work->previous_argument);
     }
+
+  if (!do_type (work, mangled, work->previous_argument))
+    return 0;
+
+  string_appends (result, work->previous_argument);
+
+  remember_type (work, start, *mangled - start);
+  return 1;
 }
 
 static void
@@ -2937,6 +3030,9 @@ remember_type (work, start, len)
 {
   char *tem;
 
+  if (work->forgetting_types)
+    return;
+
   if (work -> ntypes >= work -> typevec_size)
     {
       if (work -> typevec_size == 0)
@@ -3116,8 +3212,8 @@ forget_types (work)
      foo__FiR3fooT1T2T1T2
      __ct__3fooFiR3fooT1T2T1T2
 
-   Note that g++ bases it's type numbers starting at zero and counts all
-   previously seen types, while lucid/ARM bases it's type numbers starting
+   Note that g++ bases its type numbers starting at zero and counts all
+   previously seen types, while lucid/ARM bases its type numbers starting
    at one and only considers types after it has seen the 'F' character
    indicating the start of the function args.  For lucid/ARM style, we
    account for this difference by discarding any previously seen types when
@@ -3148,7 +3244,8 @@ demangle_args (work, mangled, declp)
        }
     }
 
-  while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+  while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+        || work->nrepeats > 0)
     {
       if ((**mangled == 'N') || (**mangled == 'T'))
        {
@@ -3195,7 +3292,7 @@ demangle_args (work, mangled, declp)
            {
              return (0);
            }
-         while (--r >= 0)
+         while (work->nrepeats > 0 || --r >= 0)
            {
              tem = work -> typevec[t];
              if (need_comma && PRINT_ARG_TYPES)
@@ -3216,18 +3313,12 @@ demangle_args (work, mangled, declp)
        }
       else
        {
-         if (need_comma & PRINT_ARG_TYPES)
-           {
-             string_append (declp, ", ");
-           }
+         if (need_comma && PRINT_ARG_TYPES)
+           string_append (declp, ", ");
          if (!do_arg (work, mangled, &arg))
-           {
-             return (0);
-           }
+           return (0);
          if (PRINT_ARG_TYPES)
-           {
-             string_appends (declp, &arg);
-           }
+           string_appends (declp, &arg);
          string_delete (&arg);
          need_comma = 1;
        }
@@ -3253,6 +3344,44 @@ demangle_args (work, mangled, declp)
   return (1);
 }
 
+/* Like demangle_args, but for demangling the argument lists of function
+   and method pointers or references, not top-level declarations.  */
+
+int
+demangle_nested_args (work, mangled, declp)
+     struct work_stuff *work;
+     const char **mangled;
+     string *declp;
+{
+  string* saved_previous_argument;
+  int result;
+  int saved_nrepeats;
+
+  /* The G++ name-mangling algorithm does not remember types on nested
+     argument lists, unless -fsquangling is used, and in that case the
+     type vector updated by remember_type is not used.  So, we turn
+     off remembering of types here.  */
+  ++work->forgetting_types;
+
+  /* For the repeat codes used with -fsquangling, we must keep track of
+     the last argument.  */
+  saved_previous_argument = work->previous_argument;
+  saved_nrepeats = work->nrepeats;
+  work->previous_argument = 0;
+  work->nrepeats = 0;
+
+  /* Actually demangle the arguments.  */
+  result = demangle_args (work, mangled, declp);
+  
+  /* Restore the previous_argument field.  */
+  if (work->previous_argument)
+    string_delete (work->previous_argument);
+  work->previous_argument = saved_previous_argument;
+  work->nrepeats = saved_nrepeats;
+
+  return result;
+}
+
 static void
 demangle_function_name (work, mangled, declp, scan)
      struct work_stuff *work;