]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cplus-dem.c (string): Move definition before work_stuff.
authorMark Mitchell <mark@markmitchell.com>
Sat, 11 Jul 1998 16:20:54 +0000 (16:20 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sat, 11 Jul 1998 16:20:54 +0000 (16:20 +0000)
* cplus-dem.c (string): Move definition before work_stuff.
(work_stuff): Add volatile_type, forgetting_types,
previous_argument, and nrepeats fields.
(SCOPE_STRING): New macro.
(demangle_template): Add `remember' parameter.  Add comment.
Register the `B' code type here, if remembering.  Tidy.  Fix crash
on NULL tmpl_argvec.  Be consistent with use of tname/trawname.
(demangle_nested_args): New function.
(internal_cplus_demangle): Handle volatile-qualified member
functions.
(mop_up): Delete the previous_argument string if present.
(demangle_signature): Tidy.  Handle volatile-qualified member
functions.  Handle back-references using the `B' code.  Use extra
parameter to demangle_template and SCOPE_STRING where appropriate.
(demangle_template_value_parm): Fix thinko; 'B' is not an integral
code.
(demangle_class): Use SCOPE_STRING.
(gnu_special): Pass additional argument to demangle_template.
Use SCOPE_STRING.
(demangle_qualified): Save qualified types for later
back-references.  Handle constructors and destructors for template
types correctly.
(do_type): Tidy.  Use SCOPE_STRING.  Pass extra argument to
demangle_template.  Use demangled_nested_args.  Don't remember
qualified types here; that's now done in demangle_qualified.
Similarly for templates.
(do_arg): Improve commment.  Handle 'n' repeat code.
(remember_type): Check forgetting_types.
(demangle_args): Deal with 'n' repeat codes.  Tidy.
* method.c (flush_repeats): Add nrepeats parameter.
(issue_nrepeats): Likewise.
(is_back_referenceable_type): New function.  Don't back-reference
TEMPLATE_TYPE_PARMs as well as simple types like integers.
(build_mangled_name_for_type): Likewise.
(build_mangled_name_for_type_with_Gcode): Likewise.
(lasttype): Remove.
(nrepeats): Likewise.
(Nrepeats): Likewise.
(start_squangling): Don't clear the variables removed above.
(end_squangling): Likewise.
(flush_repeats): Tidy.  Use nrepeats parameter rather than
Nrepeats global.
(issue_nrepeats): Likewise, but with nrepeats global.  Use
is_backreferenceable_type.
(build_overload_nested_name): Tidy.  Add comment.  Use
build_mangled_name_for_type.
(build_underscore_int): Comment.
(build_overload_scope_ref): Use build_mangled_name_for_type.
(build_overload_int): Likewise.
(build_template_template_parm_names): Tidy.
(build_template_parm_names): Use build_mangled_name_for_type.
(build_overload_identifier): Add comments.
(build_mangled_name_for_type_with_Gcode): Split out from
build_mangled_name.
(build_mangled_name_for_type): Use it.
(build_mangled_name): Rework to use build_mangled_name_for_type
and to not use global nrepeats/Nrepeats.  Tidy.
(process_modifiers): Tidy.
(check_btype): Use is_backreferenceable_type.  Add comment.
Rename `node' to `type'.
(process_overload_item): Set numeric_output_need_bar here.
Use build_mangled_name_for_type.  Tidy.
(build_decl_overload_real): Tidy.  Don't use Nrepeats.  Use
build_mangled_name_for_type.

From-SVN: r21062

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/method.c
gcc/cplus-dem.c

index 6d193264c50991cd1501d7d4b680613d916c61ad..472cbd3cb15b35542ddcafe93f65fb10aff56928 100644 (file)
@@ -1,3 +1,35 @@
+Sat Jul 11 16:19:48 1998  Mark Mitchell  <mark@markmitchell.com>
+
+       * cplus-dem.c (string): Move definition before work_stuff.
+       (work_stuff): Add volatile_type, forgetting_types,
+       previous_argument, and nrepeats fields.
+       (SCOPE_STRING): New macro.
+       (demangle_template): Add `remember' parameter.  Add comment.
+       Register the `B' code type here, if remembering.  Tidy.  Fix crash
+       on NULL tmpl_argvec.  Be consistent with use of tname/trawname.
+       (demangle_nested_args): New function.
+       (internal_cplus_demangle): Handle volatile-qualified member
+       functions. 
+       (mop_up): Delete the previous_argument string if present.
+       (demangle_signature): Tidy.  Handle volatile-qualified member
+       functions.  Handle back-references using the `B' code.  Use extra
+       parameter to demangle_template and SCOPE_STRING where appropriate.
+       (demangle_template_value_parm): Fix thinko; 'B' is not an integral
+       code. 
+       (demangle_class): Use SCOPE_STRING.
+       (gnu_special): Pass additional argument to demangle_template.
+       Use SCOPE_STRING.
+       (demangle_qualified): Save qualified types for later
+       back-references.  Handle constructors and destructors for template
+       types correctly.
+       (do_type): Tidy.  Use SCOPE_STRING.  Pass extra argument to
+       demangle_template.  Use demangled_nested_args.  Don't remember
+       qualified types here; that's now done in demangle_qualified.
+       Similarly for templates.
+       (do_arg): Improve commment.  Handle 'n' repeat code.
+       (remember_type): Check forgetting_types.
+       (demangle_args): Deal with 'n' repeat codes.  Tidy.
+       
 Sat Jul 11 02:59:08 1998  Richard Earnshaw  <rearnsha@arm.com>
 
        * arm.md (extendhisi2_mem, movhi, movhi_bytes): Propagate the volatile
index eac51c99adfeda0723f35fa37ad82f63439284be..d72b442df2b3c94809e565e978de256e935b63b6 100644 (file)
@@ -1,5 +1,41 @@
 1998-07-11  Mark Mitchell  <mark@markmitchell.com>
 
+       * method.c (flush_repeats): Add nrepeats parameter.
+       (issue_nrepeats): Likewise.
+       (is_back_referenceable_type): New function.  Don't back-reference
+       TEMPLATE_TYPE_PARMs as well as simple types like integers.
+       (build_mangled_name_for_type): Likewise.
+       (build_mangled_name_for_type_with_Gcode): Likewise.
+       (lasttype): Remove.
+       (nrepeats): Likewise.
+       (Nrepeats): Likewise.
+       (start_squangling): Don't clear the variables removed above.
+       (end_squangling): Likewise.
+       (flush_repeats): Tidy.  Use nrepeats parameter rather than
+       Nrepeats global.
+       (issue_nrepeats): Likewise, but with nrepeats global.  Use
+       is_backreferenceable_type.
+       (build_overload_nested_name): Tidy.  Add comment.  Use
+       build_mangled_name_for_type.
+       (build_underscore_int): Comment.
+       (build_overload_scope_ref): Use build_mangled_name_for_type.
+       (build_overload_int): Likewise.
+       (build_template_template_parm_names): Tidy.
+       (build_template_parm_names): Use build_mangled_name_for_type.
+       (build_overload_identifier): Add comments.
+       (build_mangled_name_for_type_with_Gcode): Split out from
+       build_mangled_name.
+       (build_mangled_name_for_type): Use it.
+       (build_mangled_name): Rework to use build_mangled_name_for_type
+       and to not use global nrepeats/Nrepeats.  Tidy.
+       (process_modifiers): Tidy.
+       (check_btype): Use is_backreferenceable_type.  Add comment.
+       Rename `node' to `type'.
+       (process_overload_item): Set numeric_output_need_bar here.
+       Use build_mangled_name_for_type.  Tidy.
+       (build_decl_overload_real): Tidy.  Don't use Nrepeats.  Use
+       build_mangled_name_for_type.
+
        * pt.c (push_template_decl_real): Don't look at DECL_TEMPLATE_INFO
        for TYPE_DECLs.
 
index 51a4abaab8d7af45ffaf9fd9d8a97d8ef47d42b6..23f52c2679d9fa620d29b85814e50a290c4fcd41 100644 (file)
@@ -57,14 +57,14 @@ static char *scratch_firstobj;
 
 static void icat PROTO((HOST_WIDE_INT));
 static void dicat PROTO((HOST_WIDE_INT, HOST_WIDE_INT));
-static void flush_repeats PROTO((tree));
+static void flush_repeats PROTO((int, tree));
 static void build_overload_identifier PROTO((tree));
 static void build_overload_nested_name PROTO((tree));
 static void build_overload_int PROTO((tree, int));
 static void build_overload_identifier PROTO((tree));
 static void build_qualified_name PROTO((tree));
 static void build_overload_value PROTO((tree, tree, int));
-static void issue_nrepeats PROTO((tree));
+static void issue_nrepeats PROTO((int, tree));
 static char *build_mangled_name PROTO((tree,int,int));
 static void process_modifiers PROTO((tree));
 static void process_overload_item PROTO((tree,int));
@@ -82,7 +82,10 @@ static int check_ktype PROTO((tree, int));
 static int issue_ktype PROTO((tree));
 static void build_overload_scope_ref PROTO((tree));
 static void build_mangled_template_parm_index PROTO((char *, tree));
+static int is_back_referenceable_type PROTO((tree));
 static int check_btype PROTO((tree));
+static void build_mangled_name_for_type PROTO((tree));
+static void build_mangled_name_for_type_with_Gcode PROTO((tree, int));
 
 # define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)
 # define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))
@@ -173,7 +176,6 @@ do_inline_function_hair (type, friend_list)
 /* type tables for K and B type compression */
 static tree *btypelist = NULL;
 static tree *ktypelist = NULL;
-static tree lasttype = NULL;
 static int maxbsize = 0;
 static int maxksize = 0;
 
@@ -181,9 +183,6 @@ static int maxksize = 0;
 static int maxbtype = 0;
 static int maxktype = 0;
 
-/* Number of occurrences of last b type seen.  */
-static int nrepeats = 0;
-
 /* Array of types seen so far in top-level call to `build_mangled_name'.
    Allocated and deallocated by caller.  */
 static tree *typevec = NULL;
@@ -192,9 +191,6 @@ static int  typevec_size;
 /* Number of types interned by `build_mangled_name' so far.  */
 static int maxtype = 0;
 
-/* Number of occurrences of last type seen.  */
-static int Nrepeats = 0;
-
 /* Nonzero if we should not try folding parameter types.  */
 static int nofold;
 
@@ -207,9 +203,7 @@ start_squangling ()
 {
   if (flag_do_squangling)
     {
-      lasttype = NULL;
       nofold = 0;
-      nrepeats = 0;
       maxbtype = 0;
       maxktype = 0;
       maxbsize = 50;
@@ -224,7 +218,6 @@ end_squangling ()
 {
   if (flag_do_squangling)
     {
-      lasttype = NULL;
       if (ktypelist)
         free (ktypelist);
       if (btypelist)
@@ -305,8 +298,9 @@ dicat (lo, hi)
   OB_PUTC ('0' + ulo);
 }
 
-static __inline void
-flush_repeats (type)
+__inline void
+flush_repeats (nrepeats, type)
+     int nrepeats;
      tree type;
 {
   int tindex = 0;
@@ -314,50 +308,73 @@ flush_repeats (type)
   while (typevec[tindex] != type)
     tindex++;
 
-  if (Nrepeats > 1)
+  if (nrepeats > 1)
     {
       OB_PUTC ('N');
-      icat (Nrepeats);
-      if (Nrepeats > 9)
+      icat (nrepeats);
+      if (nrepeats > 9)
        OB_PUTC ('_');
     }
   else
     OB_PUTC ('T');
-  Nrepeats = 0;
   icat (tindex);
   if (tindex > 9)
     OB_PUTC ('_');
 }
 
+/* Returns nonzero iff this is a type to which we will want to make
+   back-references (using the `B' code).  */
 
-/* issue squangling type repeating */
-static void
-issue_nrepeats (lasttype)
-     tree lasttype;
+int
+is_back_referenceable_type (type)
+     tree type;
 {
-  if (nrepeats == 1)
+  if (btypelist == NULL)
+    /* We're not generating any back-references.  */
+    return 0;
+
+  switch (TREE_CODE (type)) 
     {
-      switch (TREE_CODE (lasttype))
-        {
-          case INTEGER_TYPE:
-          case REAL_TYPE:
-          case VOID_TYPE:
-          case BOOLEAN_TYPE:
-            process_overload_item (lasttype, FALSE);
-            nrepeats = 0;
-            return;
-
-          default:
-            break;
-        }
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      /* These types have single-character manglings, so there's no
+        point in generating back-references.  */
+      return 0;         
+
+    case TEMPLATE_TYPE_PARM:
+      /* It would be a bit complex to demangle signatures correctly if
+        we generated back-references to these, and the manglings of
+        type parameters are short.  */
+      return 0;
+
+    default:
+      return 1;
     }
-  OB_PUTC ('n');
-  icat (nrepeats);
-  if (nrepeats > 9)
-    OB_PUTC ('_');
-  nrepeats = 0;
 }
 
+/* Issue the squangling code indicating NREPEATS repetitions of TYPE,
+   which was the last parameter type output.  */
+
+static void
+issue_nrepeats (nrepeats, type)
+     int nrepeats;
+     tree type;
+{
+  if (nrepeats == 1 && !is_back_referenceable_type (type))
+    /* For types whose manglings are short, don't bother using the
+       repetition code if there's only one repetition, since the
+       repetition code will be about as long as the ordinary mangling.  */ 
+    build_mangled_name_for_type (type);
+  else
+    {
+      OB_PUTC ('n');
+      icat (nrepeats);
+      if (nrepeats > 9)
+       OB_PUTC ('_');
+    }
+}
 
 /* Check to see if a tree node has been entered into the Kcode typelist    */
 /* if not, add it. Return -1 if it isn't found, otherwise return the index */
@@ -410,12 +427,16 @@ issue_ktype (decl)
     }
   return FALSE;
 }
+  
+/* Build a representation for DECL, which may be an entity not at
+   global scope.  If so, a marker indicating that the name is
+   qualified has already been output, but the qualifying context has
+   not.  */
 
 static void
 build_overload_nested_name (decl)
      tree decl;
 {
-
   tree context;
 
   if (ktypelist && issue_ktype (decl))
@@ -433,7 +454,7 @@ build_overload_nested_name (decl)
        rather than 'T' or some such. */
     if (TREE_CODE (context) == TEMPLATE_TYPE_PARM
         || TREE_CODE (context) == TEMPLATE_TEMPLATE_PARM)
-      build_mangled_name (context, 0, 0);
+      build_mangled_name_for_type (context);
     else
     {
       if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
@@ -462,6 +483,9 @@ build_overload_nested_name (decl)
     build_overload_identifier (decl);
 }
 
+/* Output the decimal representation of I.  If I > 9, the decimal
+   representation is preceeded and followed by an underscore.  */
+
 static void
 build_underscore_int (i)
      int i;
@@ -479,7 +503,7 @@ build_overload_scope_ref (value)
 {
   OB_PUTC2 ('Q', '2');
   numeric_output_need_bar = 0;
-  build_mangled_name (TREE_OPERAND (value, 0), 0, 0);
+  build_mangled_name_for_type (TREE_OPERAND (value, 0));
   build_overload_identifier (TREE_OPERAND (value, 1));
 }
 
@@ -539,7 +563,7 @@ build_overload_int (value, in_template)
                /* We can get here with sizeof, e.g.:
                     
                   template <class T> void f(A<sizeof(T)>);  */
-               process_overload_item (operand, 0);
+               build_mangled_name_for_type (operand);
              else if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
                build_overload_int (operand, in_template);
              else
@@ -825,10 +849,8 @@ build_template_template_parm_names (parmlist)
          build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
        }
       else
-       {
-         /* It's a PARM_DECL.  */
-         build_mangled_name (TREE_TYPE (parm), 0, 0);
-       }
+       /* It's a PARM_DECL.  */
+       build_mangled_name_for_type (TREE_TYPE (parm));
     }
 }
 
@@ -853,14 +875,14 @@ build_template_parm_names (parmlist, arglist)
        {
          /* This parameter is a type.  */
          OB_PUTC ('Z');
-         build_mangled_name (arg, 0, 0);
+         build_mangled_name_for_type (arg);
        }
       else if (TREE_CODE (parm) == TEMPLATE_DECL)
        {
          /* This parameter is a template. */
          if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
            /* Output parameter declaration, argument index and level */
-           build_mangled_name (arg, 0, 0);
+           build_mangled_name_for_type (arg);
          else
            {
              /* A TEMPLATE_DECL node, output the parameter declaration 
@@ -876,12 +898,14 @@ build_template_parm_names (parmlist, arglist)
        {
          parm = tsubst (parm, arglist, NULL_TREE);
          /* It's a PARM_DECL.  */
-         build_mangled_name (TREE_TYPE (parm), 0, 0);
+         build_mangled_name_for_type (TREE_TYPE (parm));
          build_overload_value (parm, arg, uses_template_parms (arglist));
        }
     }
  }
 
+/* Output the representation for NAME, which is either a TYPE_DECL or
+   an IDENTIFIER.  */
 
 static void
 build_overload_identifier (name)
@@ -895,6 +919,7 @@ build_overload_identifier (name)
                                       (TREE_TYPE (name))))
              == FUNCTION_DECL)))
     {
+      /* NAME is the TYPE_DECL for a template specialization.  */
       tree template, parmlist, arglist, tname;
       template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
       arglist = innermost_args (TREE_VALUE (template), 0);
@@ -969,6 +994,32 @@ build_qualified_name (decl)
   build_overload_nested_name (decl);
 }
 
+/* Output the mangled representation for TYPE.  If EXTRA_GCODE is
+   non-zero, mangled names for structure/union types are intentionally
+   mangled differently from the method described in the ARM.  */
+
+void 
+build_mangled_name_for_type_with_Gcode (type, extra_Gcode)
+     tree type;
+     int extra_Gcode;
+{
+  if (TYPE_PTRMEMFUNC_P (type))
+    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+  type = CANONICAL_TYPE_VARIANT (type);
+  process_modifiers (type);
+  process_overload_item (type, extra_Gcode);
+}
+
+/* Like build_mangled_name_for_type_with_Gcode, but never outputs the
+   `G'.  */
+
+void
+build_mangled_name_for_type (type)
+     tree type;
+{
+  build_mangled_name_for_type_with_Gcode (type, 0);
+}
+
 /* Given a list of parameters in PARMTYPES, create an unambiguous
    overload string. Should distinguish any type that C (or C++) can
    distinguish. I.e., pointers to functions are treated correctly.
@@ -993,107 +1044,116 @@ build_overload_name (parmtypes, begin, end)
   return ret ;
 }
 
+/* Output the mangled representation for PARMTYPES.  If PARMTYPES is a
+   TREE_LIST, then it is a list of parameter types.  Otherwise,
+   PARMTYPES must be a single type.  */
+
 static char *
 build_mangled_name (parmtypes, begin, end)
      tree parmtypes;
      int begin, end;
 {
-  tree parmtype;
-
   if (begin) 
     OB_INIT ();
-  numeric_output_need_bar = 0;
 
-  if (TREE_CODE (parmtypes) != TREE_LIST)  /* just one item */
+  if (TREE_CODE (parmtypes) != TREE_LIST)  
+    /* There is only one type.  */
+    build_mangled_name_for_type (parmtypes);
+  else  
     {
-      if (TYPE_PTRMEMFUNC_P (parmtypes))
-        parmtypes = TYPE_PTRMEMFUNC_FN_TYPE (parmtypes);
-      parmtypes = CANONICAL_TYPE_VARIANT (parmtypes);
-      process_modifiers (parmtypes);
-      process_overload_item (parmtypes, FALSE);
-    }
-  else  {
-    for ( ; parmtypes!=NULL; parmtypes = TREE_CHAIN (parmtypes))
-      {
-        parmtype = CANONICAL_TYPE_VARIANT (TREE_VALUE (parmtypes));
-        if (flag_do_squangling)       /* squangling style repeats */
-          {
-            if (parmtype == lasttype) 
-              {
-                nrepeats++;
-                continue;
-              }
-            else 
-              if (nrepeats != 0) 
-                {
-                  issue_nrepeats (lasttype);
-                }
-            lasttype = parmtype;
-          }
-        else 
-          if (!nofold && typevec)
-            {
-              /* Every argument gets counted.  */
+      /* There are several types in a parameter list.  */
+      int nrepeats = 0;
+      int old_style_repeats = !flag_do_squangling && !nofold && typevec;
+      tree last_type = NULL_TREE;
+
+      for (; parmtypes && parmtypes != void_list_node;
+          parmtypes = TREE_CHAIN (parmtypes))
+       {
+         tree parmtype = CANONICAL_TYPE_VARIANT (TREE_VALUE (parmtypes));
+
+         if (old_style_repeats)
+           {
+             /* Every argument gets counted.  */
              my_friendly_assert (maxtype < typevec_size, 387);
-              typevec[maxtype++] = parmtype;
+             typevec[maxtype++] = parmtype;
+           }
 
-              if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2]
-                 && ! TYPE_FOR_JAVA (parmtype))
-                {
-                  Nrepeats++;
-                  continue;
-                }
+         if (parmtype == last_type)
+           {
+             if (flag_do_squangling 
+                 || (old_style_repeats && TREE_USED (parmtype)
+                     && !TYPE_FOR_JAVA (parmtype)))
+               {
+                 /* The next type is the same as this one.  Keep
+                    track of the repetition, and output the repeat
+                    count later.  */
+                 nrepeats++;
+                 continue;
+               }
+           }
+         else if (nrepeats != 0)
+           {
+             /* Indicate how many times the previous parameter was
+                repeated.  */
+             if (old_style_repeats)
+               flush_repeats (nrepeats, last_type);
+             else
+               issue_nrepeats (nrepeats, last_type);
+             nrepeats = 0;
+           }
+         
+         last_type = parmtype;
 
-              if (Nrepeats)
-                flush_repeats (typevec[maxtype-2]);
+         if (old_style_repeats)
+           {
+             if (nrepeats)
+               {
+                 flush_repeats (nrepeats, last_type);
+                 nrepeats = 0;
+               }
 
-              if (TREE_USED (parmtype))
-                {
+             if (TREE_USED (parmtype))
+               {
 #if 0
-                  /* We can turn this on at some point when we want
-                     improved symbol mangling.  */
-                  Nrepeats++;
+                 /* We can turn this on at some point when we want
+                    improved symbol mangling.  */
+                 nrepeats++;
 #else
-                  /* This is bug compatible with 2.7.x  */
-                  flush_repeats (parmtype);
+                 /* This is bug compatible with 2.7.x  */
+                 flush_repeats (nrepeats, parmtype);
 #endif
-                  continue;
-                }
-
-              /* Only cache types which take more than one character.  */
-              if ((parmtype != TYPE_MAIN_VARIANT (parmtype)
+                 nrepeats = 0;
+                 continue;
+               }
+             
+             /* Only cache types which take more than one character.  */
+             if ((parmtype != TYPE_MAIN_VARIANT (parmtype)
                   || (TREE_CODE (parmtype) != INTEGER_TYPE
                       && TREE_CODE (parmtype) != REAL_TYPE))
                  && ! TYPE_FOR_JAVA (parmtype))
-                TREE_USED (parmtype) = 1;
-            }
-        if (TYPE_PTRMEMFUNC_P (parmtype))
-          parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
-        process_modifiers (parmtype);
-        if (TREE_CODE(parmtype)==VOID_TYPE) 
-         {
-#if 0
-             extern tree void_list_node;
+               TREE_USED (parmtype) = 1;
+           }
+
+         /* Output the PARMTYPE.  */
+         build_mangled_name_for_type_with_Gcode (parmtype, 1);
+       }
+
+      /* Output the repeat count for the last parameter, if
+        necessary.  */
+      if (nrepeats != 0)
+       {
+         if (old_style_repeats)
+           flush_repeats (nrepeats, last_type);
+         else
+           issue_nrepeats (nrepeats, last_type);
+         nrepeats = 0;
+       }
+
+      if (!parmtypes)
+       /* The parameter list ends in an ellipsis.  */
+       OB_PUTC ('e');
+    }
 
-             /* See if anybody is wasting memory.  */
-             my_friendly_assert (parmtypes == void_list_node, 247);
-#endif
-             /* This is the end of a parameter list.  */
-             if (end) 
-                OB_FINISH ();
-             return (char *)obstack_base (&scratch_obstack);
-         }
-        process_overload_item (parmtype, TRUE);
-      }
-      if (flag_do_squangling && nrepeats != 0)
-        issue_nrepeats (lasttype);
-      else 
-        if (Nrepeats && typevec)
-          flush_repeats (typevec[maxtype-1]);
-
-      /* To get here, parms must end with `...'.  */
-      OB_PUTC ('e');
-  }
   if (end) 
     OB_FINISH ();
   return (char *)obstack_base (&scratch_obstack);
@@ -1104,63 +1164,57 @@ void
 process_modifiers (parmtype) 
      tree parmtype;
 {
-
-
   if (TREE_READONLY (parmtype))
     OB_PUTC ('C');
   if (TREE_CODE (parmtype) == INTEGER_TYPE
       && (TYPE_MAIN_VARIANT (parmtype)
          == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
       && ! TYPE_FOR_JAVA (parmtype))
-    {
-      OB_PUTC ('U');
-    }
+    OB_PUTC ('U');
   if (TYPE_VOLATILE (parmtype))
     OB_PUTC ('V');
 }
 
-/* Check to see if a tree node has been entered into the Bcode typelist 
-   if not, add it. Otherwise emit the code and return TRUE */
-static int 
-check_btype (node) 
-     tree node;
+/* Check to see if TYPE has been entered into the Bcode typelist.  If
+   so, return 1 and emit a backreference to TYPE.  Otherwise, add TYPE
+   to the list of back-referenceable types and return 0.  */
+
+int 
+check_btype (type) 
+     tree type;
 {
   int x;
 
   if (btypelist == NULL)
     return 0;
 
-  switch (TREE_CODE (node)) 
-    {
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case VOID_TYPE:
-    case BOOLEAN_TYPE:
-      return 0;         /* don't compress single char basic types */
+  if (!is_back_referenceable_type (type))
+    return 0;
 
-    default:
-      break;
-    }
+  /* We assume that our caller has put out any necessary
+     qualifiers.  */
+  type = TYPE_MAIN_VARIANT (type);
 
-  node = TYPE_MAIN_VARIANT (node);
   for (x = 0; x < maxbtype; x++) 
-    {
-      if (node == btypelist[x]) 
-        {
-          OB_PUTC ('B');
-          icat (x);
-          if (x > 9)
-            OB_PUTC ('_');
-          return 1 ;
-        }
-    }
-  /* didn't find it, so add it here */
+    if (type == btypelist[x]) 
+      {
+       OB_PUTC ('B');
+       icat (x);
+       if (x > 9)
+         OB_PUTC ('_');
+       return 1 ;
+      }
+
   if (maxbsize <= maxbtype) 
     {
+      /* Enlarge the table.  */
       maxbsize = maxbsize * 3 / 2;
       btypelist = (tree *)xrealloc (btypelist, sizeof (tree) * maxbsize); 
     }
-  btypelist[maxbtype++] = node;
+  
+  /* Register the TYPE.  */
+  btypelist[maxbtype++] = type;
+
   return 0;
 }
 
@@ -1170,6 +1224,7 @@ process_overload_item (parmtype, extra_Gcode)
   tree parmtype;
   int extra_Gcode;
 {
+  numeric_output_need_bar = 0;
 
   /* These tree types are considered modifiers for B code squangling , */
   /* and therefore should not get entries in the Btypelist             */
@@ -1206,7 +1261,7 @@ process_overload_item (parmtype, extra_Gcode)
     case POINTER_TYPE:
       OB_PUTC ('P');
     more:
-      build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+      build_mangled_name_for_type (TREE_TYPE (parmtype));
       return;
       break;
 
@@ -1214,77 +1269,57 @@ process_overload_item (parmtype, extra_Gcode)
       break;
     }
   
-  /* check if type is already in the typelist. If not, add it now */
-
-  if (flag_do_squangling && btypelist != NULL) {
-    if (check_btype (parmtype))    /* emits the code if it finds it */
-      return;
-  }
+  if (flag_do_squangling && check_btype (parmtype)) 
+    /* If PARMTYPE is already in the list of back-referenceable types,
+       then check_btype will output the appropriate reference, and
+       there's nothing more to do.  */
+    return;
 
   switch (TREE_CODE (parmtype))
     {
     case OFFSET_TYPE:
       OB_PUTC ('O');
-      build_mangled_name (TYPE_OFFSET_BASETYPE (parmtype), 0, 0);
+      build_mangled_name_for_type (TYPE_OFFSET_BASETYPE (parmtype));
       OB_PUTC ('_');
-      build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+      build_mangled_name_for_type (TREE_TYPE (parmtype));
       break;
 
     case FUNCTION_TYPE:
     case METHOD_TYPE:
       {
-        tree firstarg = TYPE_ARG_TYPES (parmtype);
-        /* Otherwise have to implement reentrant typevecs,
-           unmark and remark types, etc.  */
-        int old_nofold = nofold;
-        if (!flag_do_squangling) {
-          nofold = 1;
-          if (Nrepeats)
-            flush_repeats (typevec[maxtype-1]);
-        }
-        else 
-          if (nrepeats != 0)
-            issue_nrepeats (lasttype);
+        tree parms = TYPE_ARG_TYPES (parmtype);
 
-        /* @@ It may be possible to pass a function type in
-           which is not preceded by a 'P'.  */
-        if (TREE_CODE (parmtype) == FUNCTION_TYPE)
-          {
-            OB_PUTC ('F');
-            if (firstarg == NULL_TREE)
-              OB_PUTC ('e');
-            else if (firstarg == void_list_node)
-              OB_PUTC ('v');
-            else
-              build_mangled_name (firstarg, 0, 0);
-          }
-        else
-          {
-            int constp = TYPE_READONLY (TREE_TYPE (TREE_VALUE (firstarg)));
-            int volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg)));
+       /* Rather than implementing a reentrant TYPEVEC, we turn off
+          repeat codes here, unless we're squangling.  Squangling
+          doesn't make use of the TYPEVEC, so there's no reentrancy
+          problem.  */
+       int old_nofold = nofold;
+       if (!flag_do_squangling)
+         nofold = 1;
+
+       if (TREE_CODE (parmtype) == METHOD_TYPE)
+         {
+           /* Mark this as a method.  */
             OB_PUTC ('M');
-            firstarg = TREE_CHAIN (firstarg);
-
-            build_mangled_name (TYPE_METHOD_BASETYPE (parmtype), 0, 0);
-            if (constp)
-              OB_PUTC ('C');
-            if (volatilep)
-              OB_PUTC ('V');
-
-            /* For cfront 2.0 compatibility.  */
-            OB_PUTC ('F');
-
-            if (firstarg == NULL_TREE)
-              OB_PUTC ('e');
-            else if (firstarg == void_list_node)
-              OB_PUTC ('v');
-            else
-              build_mangled_name (firstarg, 0, 0);
-          }
+           /* Output the class of which this method is a member.  */
+            build_mangled_name_for_type (TYPE_METHOD_BASETYPE (parmtype));
+           /* Output any qualifiers for the `this' parameter.  */
+           process_modifiers (TREE_TYPE (TREE_VALUE (parms)));
+         }
 
-        /* Separate args from return type.  */
+       /* Output the parameter types.  */
+       OB_PUTC ('F');
+       if (parms == NULL_TREE)
+         OB_PUTC ('e');
+       else if (parms == void_list_node)
+         OB_PUTC ('v');
+       else
+         build_mangled_name (parms, 0, 0);
+
+        /* Output the return type.  */
         OB_PUTC ('_');
-        build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+        build_mangled_name_for_type (TREE_TYPE (parmtype));
+
         nofold = old_nofold;
         break;
       }
@@ -1350,7 +1385,7 @@ process_overload_item (parmtype, extra_Gcode)
 
     case COMPLEX_TYPE:
       OB_PUTC ('J');
-      build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+      build_mangled_name_for_type (TREE_TYPE (parmtype));
       break;
 
     case VOID_TYPE:
@@ -1492,41 +1527,20 @@ build_decl_overload_real (dname, parms, ret_type, tparms, targs,
      and figure out its name without any extra encoding.  */
 
   OB_PUTC2 ('_', '_');
-  if (for_method)
-    {
-#if 0
-      /* We can get away without doing this.  */
-      OB_PUTC ('M');
-#endif
-      if (tparms != NULL_TREE)
-       OB_PUTC ('H');
-      {
-       tree this_type = TREE_VALUE (parms);
-
-       if (TREE_CODE (this_type) == RECORD_TYPE)  /* a signature pointer */
-         parms = temp_tree_cons (NULL_TREE, SIGNATURE_TYPE (this_type),
-                                 TREE_CHAIN (parms));
-       else
-         parms = temp_tree_cons (NULL_TREE, TREE_TYPE (this_type),
-                                 TREE_CHAIN (parms));
-      }
-    }
-  else if (tparms)
-    OB_PUTC ('H');
-  /* XXX this works only if we call this in the same namespace
-     as the declaration. Unfortunately, we don't have the _DECL,
-     only its name */
-  else if (current_namespace == global_namespace)
-    OB_PUTC ('F');
 
   if (tparms)
     {
+      OB_PUTC ('H');
       build_template_parm_names (tparms, targs);
       OB_PUTC ('_');
     }
-
-  /* qualify with namespace */
-  if (!for_method && current_namespace != global_namespace)
+  else if (!for_method && current_namespace == global_namespace)
+    /* XXX this works only if we call this in the same namespace
+       as the declaration. Unfortunately, we don't have the _DECL,
+       only its name */
+    OB_PUTC ('F');
+  else if (!for_method)
+    /* qualify with namespace */
     build_qualified_name (current_namespace);
 
   if (parms == NULL_TREE)
@@ -1538,7 +1552,6 @@ build_decl_overload_real (dname, parms, ret_type, tparms, targs,
       if (!flag_do_squangling)    /* Allocate typevec array. */
         {
           maxtype = 0;
-          Nrepeats = 0;
          typevec_size = list_length (parms);
          if (!for_method && current_namespace != global_namespace)
            /* the namespace of a global function needs one slot */
@@ -1546,15 +1559,29 @@ build_decl_overload_real (dname, parms, ret_type, tparms, targs,
           typevec = (tree *)alloca (typevec_size * sizeof (tree));
         }
       nofold = 0;
+
       if (for_method)
        {
-         build_mangled_name (TREE_VALUE (parms), 0, 0);
+         tree this_type = TREE_VALUE (parms);
 
-          if (!flag_do_squangling) {
-           my_friendly_assert (maxtype < typevec_size, 387);
-            typevec[maxtype++] = TREE_VALUE (parms);
-            TREE_USED (TREE_VALUE (parms)) = 1;
-          }
+         if (TREE_CODE (this_type) == RECORD_TYPE)  /* a signature pointer */
+           this_type = SIGNATURE_TYPE (this_type);
+         else
+           this_type = TREE_TYPE (this_type);
+
+         build_mangled_name_for_type (this_type);
+
+          if (!flag_do_squangling) 
+           {
+             my_friendly_assert (maxtype < typevec_size, 387);
+             typevec[maxtype++] = this_type;
+             TREE_USED (this_type) = 1;
+
+             /* By setting up PARMS in this way, the loop below will
+                automatically clear TREE_USED on THIS_TYPE.  */
+             parms = temp_tree_cons (NULL_TREE, this_type,
+                                     TREE_CHAIN (parms));
+           }
 
          if (TREE_CHAIN (parms))
            build_mangled_name (TREE_CHAIN (parms), 0, 0);
@@ -1594,7 +1621,7 @@ build_decl_overload_real (dname, parms, ret_type, tparms, targs,
     {
       /* Add the return type. */
       OB_PUTC ('_');
-      build_mangled_name (ret_type, 0, 0);
+      build_mangled_name_for_type (ret_type);
     }
 
   OB_FINISH ();
index b05c948481bb0e2241efa3f7a81e69454df53ec2..ce67d2288e4e6bf76e6b7a55ec316ed4f716a897 100644 (file)
@@ -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,10 @@ 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) \
+  (((work)->options & DMGL_JAVA) ? "." : "::")
+
 #define ARM_VTABLE_STRING "__vtbl__"   /* Lucid/ARM virtual table prefix */
 #define ARM_VTABLE_STRLEN 8            /* strlen (ARM_VTABLE_STRING) */
 
@@ -247,7 +257,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 +335,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 *));
 
@@ -631,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'))
     {
@@ -677,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);
 }
 
@@ -727,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.  */
@@ -795,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;
 
@@ -826,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':
@@ -852,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
@@ -884,12 +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, (work -> options & DMGL_JAVA) ? "." : "::");
+         string_append(&tname, SCOPE_STRING (work));
          string_prepends(declp, &tname);
          if (work -> destructor & 1)
            {
@@ -936,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)++;
@@ -993,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);
 }
 
@@ -1211,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;
@@ -1360,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;
@@ -1375,10 +1418,13 @@ demangle_template (work, mangled, tname, trawname, is_type)
   const char *start;
   int is_java_array = 0;
   string temp;
+  int bindex;
 
   (*mangled)++;
   if (is_type)
     {
+      if (remember)
+       bindex = register_Btype (work);
       start = *mangled;
       /* get template name */
       if (**mangled == 'z')
@@ -1391,9 +1437,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]);
@@ -1406,7 +1451,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
@@ -1415,13 +1460,13 @@ demangle_template (work, mangled, tname, trawname, is_type)
            {
              return (0);
            }
-         if (trawname)
-           string_appendn (trawname, *mangled, r);
          is_java_array = (work -> options & DMGL_JAVA)
            && strncmp (*mangled, "JArray1Z", 8) == 0;
          if (! is_java_array)
            {
              string_appendn (tname, *mangled, r);
+             if (trawname)
+               string_appendn (trawname, *mangled, r);
            }
          *mangled += r;
        }
@@ -1565,6 +1610,9 @@ demangle_template (work, mangled, tname, trawname, is_type)
       string_append (tname, ">");
     }
   
+  if (is_type && remember)
+    remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
+
   /*
     if (work -> static_type)
     {
@@ -1722,7 +1770,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, (work -> options & DMGL_JAVA) ? "." : "::");
+      string_prepend (declp, SCOPE_STRING (work));
       string_prepends (declp, &class_name);
       success = 1;
     }
@@ -1996,7 +2044,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]))
@@ -2024,8 +2073,7 @@ gnu_special (work, mangled, declp)
            {
              if (p != NULL)
                {
-                 string_append (declp,
-                                (work -> options & DMGL_JAVA) ? "." : "::");
+                 string_append (declp, SCOPE_STRING (work));
                  (*mangled)++;
                }
            }
@@ -2051,7 +2099,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);
@@ -2063,7 +2111,7 @@ gnu_special (work, mangled, declp)
          /* Consumed everything up to the cplus_marker, append the
             variable name.  */
          (*mangled)++;
-         string_append (declp, (work -> options & DMGL_JAVA) ? "." : "::");
+         string_append (declp, SCOPE_STRING (work));
          n = strlen (*mangled);
          string_appendn (declp, *mangled, n);
          (*mangled) += n;
@@ -2104,7 +2152,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);
@@ -2236,13 +2284,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')
     {
@@ -2315,18 +2370,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;
@@ -2341,60 +2402,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, (work -> options & DMGL_JAVA) ? "." : "::");
-        }
+       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, (work -> options & DMGL_JAVA) ? "." : "::");
+      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, (work -> options & DMGL_JAVA) ? "." : "::");
-       }
+       string_append (&temp, SCOPE_STRING (work));
       string_prepends (result, &temp);
     }
 
+  string_delete (&last_name);
   string_delete (&temp);
   return (success);
 }
@@ -2542,15 +2591,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':
@@ -2568,7 +2616,7 @@ do_type (work, mangled, result)
              }
 
            string_append (&decl, ")");
-           string_prepend (&decl, (work -> options & DMGL_JAVA) ? "." : "::");
+           string_prepend (&decl, SCOPE_STRING (work));
            if (isdigit (**mangled)) 
              {
                n = consume_count (mangled);
@@ -2584,7 +2632,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);
@@ -2612,7 +2661,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;
@@ -2673,10 +2722,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;
       }
 
@@ -2906,9 +2952,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;
       }
@@ -2920,7 +2964,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)
@@ -2928,17 +2974,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
@@ -2949,6 +3045,9 @@ remember_type (work, start, len)
 {
   char *tem;
 
+  if (work->forgetting_types)
+    return;
+
   if (work -> ntypes >= work -> typevec_size)
     {
       if (work -> typevec_size == 0)
@@ -3160,7 +3259,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'))
        {
@@ -3207,7 +3307,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)
@@ -3228,18 +3328,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;
        }
@@ -3265,6 +3359,42 @@ 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;
+}
+
 static void
 demangle_function_name (work, mangled, declp, scan)
      struct work_stuff *work;