OSDN Git Service

merge from gcc repository
authorDJ Delorie <dj@delorie.com>
Thu, 12 Oct 2000 02:16:48 +0000 (02:16 +0000)
committerDJ Delorie <dj@delorie.com>
Thu, 12 Oct 2000 02:16:48 +0000 (02:16 +0000)
14 files changed:
include/ChangeLog
include/splay-tree.h
libiberty/ChangeLog
libiberty/Makefile.in
libiberty/cp-demangle.c
libiberty/cplus-dem.c
libiberty/dyn-string.c
libiberty/pexecute.c
libiberty/setenv.c
libiberty/sigsetmask.c
libiberty/splay-tree.c
libiberty/vasprintf.c
libiberty/vfork.c
libiberty/xexit.c

index b6ea943..c6ad3b4 100644 (file)
@@ -1,3 +1,7 @@
+2000-10-11  Mark Mitchell  <mark@codesourcery.com>
+
+       * splay-tree.h (splay_tree_predecessor): Declare.
+
 2000-09-29  Hans-Peter Nilsson  <hp@axis.com>
 
        * dis-asm.h: Declare cris_get_disassembler, not print_insn_cris.
index 39882a4..f53f855 100644 (file)
@@ -1,5 +1,5 @@
 /* A splay-tree datatype.  
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
    Contributed by Mark Mitchell (mark@markmitchell.com).
 
 This file is part of GNU CC.
@@ -104,6 +104,12 @@ extern void splay_tree_remove              PARAMS((splay_tree,
 extern splay_tree_node splay_tree_lookup   
                                         PARAMS((splay_tree,
                                                splay_tree_key));
+extern splay_tree_node splay_tree_predecessor
+                                        PARAMS((splay_tree,
+                                               splay_tree_key));
+extern splay_tree_node splay_tree_successor
+                                        PARAMS((splay_tree,
+                                               splay_tree_key));
 extern int splay_tree_foreach           PARAMS((splay_tree,
                                                splay_tree_foreach_fn,
                                                void*));
index f4745f0..b78b80b 100644 (file)
@@ -1,3 +1,187 @@
+2000-10-11  DJ Delorie  <dj@redhat.com>
+
+       Merge from gcc, all 2000-10-11 entries below
+
+2000-10-11  Mark Mitchell  <mark@codesourcery.com>
+
+       * splay-tree.c (splay_tree_insert): Fix formatting.
+       
+2000-10-11  Mark Mitchell  <mark@codesourcery.com>
+
+       * splay-tree.c (splay_tree_predecessor): Fix typo in comment.
+       
+2000-10-11  Mark Mitchell  <mark@codesourcery.com>
+
+       * splay-tree.c (splay_tree_predecessor): New function.
+       (splay_tree_successor): Likewise.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c: Fix copyright banner.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (status_allocation_failed): Rearrange whitespace.
+       (demangle_type): Handle substitution candidates correctly in the
+       face of special substitutions.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (demangle_encoding): Rename variable.
+       (demangle_name): Rename parameter.  Handle return type
+       suppression.
+       (demangle_nested_name): Rename parameter.
+       (demangle_prefix): Likewise.  Change return type suppression.
+       (demangle_unqualified_name): Add parameter.  Flag constructors and
+       conversion operators.
+       (demangle_special_name): Fix comment.
+       (demangle_type): Rename variable.
+       (demangle_bare_function_type): Check for missing return type and
+       parameter.
+       (demangle_class_enum_type): Rename parameter.
+       (demangle_discriminator): Fix misspelling in comment.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (demangle_template_arg): Eat an `E' after an
+       <expression>.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (demangle_type_ptr): Increment position past
+       pointer and reference characters.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (demangle_nv_offset): New function.
+       (demangle_v_offset): Likewise.
+       (demangle_call_offset): Likewise.
+       (demangle_special_name): Update thunk demangling to comply with
+       ABI changes.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (ANONYMOUS_NAMESPACE_PREFIX): New macro.
+       (substitution_def): Remove template_parm_number.
+       (NOT_TEMPLATE_PARM): Remove.
+       (result_insert_string): New macro.
+       (result_insert): Likewise.
+       (result_insert_char): Likewise.
+       (substitution_add): Remove last parameter.  Don't store template
+       parm number.
+       (BFT_NO_RETURN_TYPE): Define as NULL.
+       (demangle_encoding): Adjust call to demangle_bare_function_type.
+       (demangle_name): Adjust substitution.  Adjust call to
+       substitution_add.
+       (demangle_prefix): Adjust call to substitution_add.
+       (demangle_identifier): Handle anonymous namespaces.
+       (demangle_operator_name): Change demangling of vendor-extended
+       operator to match ABI changes.
+       (demangle_type_ptr): Change parameters.  Make recursive.  Handle
+       substitutions here.
+       (demangle_type): Adjust calls to demangle_template_param,
+       substitution_add, and demangle_type_ptr.  Fix substitution of
+       templated types.
+       (demangle_function_type): Change parameter to a pointer.
+       (demangle_bare_function_type): Likewise.  Adjust insertion point.
+       (demangle_template_param): Remove last parameter.
+       (demangle_expr_primary): Remove unused variable.  Adjust call to
+       demangle_template_param.
+       (is_mangled_char): Accept `$' and `.'.
+       * cplus-dem.c (gnu_new_abi_symbol_characters): Add '$' and '.'.
+       * dyn-string.c (dyn_string_insert_char): New function.
+       
+2000-10-11  Richard Henderson  <rth@cygnus.com>
+
+       * Makefile.in (md5.o): Depend on config.h.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (demangle_name): Initialize template_p in local
+       name case.  Don't re-add substitutions as candidates.
+       (demangle_nested_name): Use <unqualified-name>.
+       (demangle_prefix): Likewise.  Don't add template names as
+       substitution candidates twice, or re-add a substitution or the
+       last prefix component.
+       (demangle_local_name): Adjust output format.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (result_add_separated_char): Change parameter to
+       int.
+       (substitution_add): Don't check for duplicates.  Check if
+       previously allocated size is zero.
+       (demangle_name): Remove duplicate check for std substitution.
+       Clear template flag appropriately.
+       (demangle_prefix): Remove argument to demangle_substitution.
+       Don't check that template flag is already set.
+       (demangle_operator_name): Add pt operator.
+       (demangle_type): Don't treat r as built-in type.  Remove argument
+       to demangle_substitution.  Fix substitution candidate mechanics.
+       Handle <template-template-parm>s.  Improve comments.
+       (demangle_template_param): Don't handle template arg lists here.
+       (demangle_substitution): Remove parameter.
+       (print_usage): Remove extra fprintf option.
+       
+2000-10-11  Greg McGary  <greg@mcgary.org>
+
+       * libiberty/random.c (end_ptr): Revert previous change.
+       
+2000-10-11  Greg McGary  <greg@mcgary.org>
+
+       * libiberty/cplus-dem.c (cplus_demangle_opname, cplus_mangle_opname,
+       demangle_expression, demangle_function_name): Use ARRAY_SIZE.
+       * libiberty/random.c (end_ptr): Likewise.
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (result_close_template_list): Remove function.
+       (result_add_separated_char): New function.
+       (result_open_template_list): New macro.
+       (result_close_template_list): Likewise.
+       (demangle_prefix): Don't set template_p if the
+       prefix ends with a ctor name.
+       (demangle_type_ptr): Remove duplicate RETURN_IF_ERROR.
+       (demangle_type): Check for template args after substitution.
+       (demangle_template_args): Use result_open_template_list.
+       
+2000-10-11  Zack Weinberg  <zack@wolery.cumb.org>
+
+       * pexecute.c:  Don't use vfork.  Initialize 'pid' before retry loop.
+       
+2000-10-11  RodneyBrown  <RodneyBrown@pmsc.com>
+
+       Jeff Law <law@cygnus.com>
+       * getcwd.c: Include string.h, stdlib.h for prototypes
+       * Makefile.in (rename.o, waitpid.o): Depend on config.h
+       * rename.c: Include config.h, unistd.h
+       * waitpid.c: Include config.h, sys/wait.h
+       
+2000-10-11  Alex Samuel  <samuel@codesourcery.com>
+
+       * cp-demangle.c (demangle_ctor_dtor_name): Remove not-in-charge
+       allocating ctor mangling.
+       (demangle_array_type): Handle empty and non-constant array length.
+       
+2000-10-11  Mike Stump  <mrs@wrs.com>
+
+       * Makefile.in (xexit.o): Add dependency for config.h in xexit.c.
+       * (vasprintf.o): Add dependency for config.h in vasprintf.c.
+       
+2000-10-11  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * cp-demangle.c (cp_demangle_type): Wrap in IN_LIBGCC2.
+       * setenv.c (setenv): Initialize variable `ep'.
+       * sigsetmask.c (abort): Prototype.
+       * vasprintf.c: Include config.h.  Check ANSI_PROTOTYPES, not
+       __STDC__ for stdarg.h include.
+       (int_vasprintf): Prototype.
+       (checkit): Prototype.  Use VPARAMS/ANSI_PROTOTYPES/VA_START in
+       definition.  Cast `global_total_width' in comparison.
+       (main): Prototype.  Return a value.
+       * vfork.c (fork): Prototype.
+       * xexit.c: Include config.h.
+
 2000-09-25  Michael Sokolov  <msokolov@ivan.Harhan.ORG>
 
        * md5.c: #include "ansidecl.h".
index 58c07c4..62a97dc 100644 (file)
@@ -276,6 +276,7 @@ getruntime.o: config.h $(INCDIR)/libiberty.h
 hex.o: $(INCDIR)/libiberty.h
 floatformat.o: $(INCDIR)/floatformat.h
 mkstemps.o: config.h
+md5.o: config.h
 objalloc.o: config.h $(INCDIR)/objalloc.h
 obstack.o: config.h $(INCDIR)/obstack.h
 partition.o: config.h $(INCDIR)/partition.h
@@ -289,8 +290,9 @@ strerror.o: config.h $(INCDIR)/libiberty.h
 strsignal.o: config.h $(INCDIR)/libiberty.h
 strtol.o: config.h
 strtoul.o: config.h
+vasprintf.o: config.h
 xatexit.o: $(INCDIR)/libiberty.h
-xexit.o: $(INCDIR)/libiberty.h
+xexit.o: config.h $(INCDIR)/libiberty.h
 xmalloc.o: config.h $(INCDIR)/libiberty.h
 xmemdup.o: config.h $(INCDIR)/libiberty.h
 xstrdup.o: config.h $(INCDIR)/libiberty.h
index 1eb2402..e543edf 100644 (file)
@@ -1,7 +1,9 @@
 /* Demangler for IA64 / g++ standard C++ ABI.
-   Copyright (C) 2000 CodeSourcery LLC.
+   Copyright (C) 2000 Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>. 
 
+   This file is part of GNU CC.
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
@@ -21,7 +23,8 @@
    the IA64 / g++ standard C++ ABI.  Use the cp_demangle function to
    demangle a mangled name, or compile with the preprocessor macro
    STANDALONE_DEMANGLER defined to create a demangling filter
-   executable.  */
+   executable (functionally similar to c++filt, but includes this
+   demangler only).  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
   (((CHAR) >= 'a' && (CHAR) <= 'z')                                     \
    || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
 
+/* The prefix prepended by GCC to an identifier represnting the
+   anonymous namespace.  */
+#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
+
 /* If flag_verbose is zero, some simplifications will be made to the
    output to make it easier to read and supress details that are
    generally not of interest to the average C++ programmer.
@@ -91,17 +98,10 @@ struct substitution_def
   /* The demangled text of the substitution.  */
   dyn_string_t text;
 
-  /* The template parameter that this represents, indexed from zero.
-     If this is not a template paramter number, the value is
-     NOT_TEMPLATE_PARM.  */
-  int template_parm_number;
-
   /* Whether this substitution represents a template item.  */
   int template_p : 1;
 };
 
-#define NOT_TEMPLATE_PARM (-1)
-
 /* Data structure representing a template argument list.  */
 
 struct template_arg_list_def
@@ -172,7 +172,7 @@ typedef const char *status_t;
 #define STATUS_INTERNAL_ERROR           "Internal error."
 
 /* This status code indicates a failure in malloc or realloc.  */
-static const charconst status_allocation_failed = "Allocation failed.";
+static const char *const status_allocation_failed = "Allocation failed.";
 #define STATUS_ALLOCATION_FAILED        status_allocation_failed
 
 /* Non-zero if STATUS indicates that no error has occurred.  */
@@ -196,8 +196,8 @@ static string_list_t string_list_new
   PARAMS ((int));
 static void string_list_delete
   PARAMS ((string_list_t));
-static status_t result_close_template_list 
-  PARAMS ((demangling_t));
+static status_t result_add_separated_char
+  PARAMS ((demangling_t, int));
 static status_t result_push
   PARAMS ((demangling_t));
 static string_list_t result_pop
@@ -205,7 +205,7 @@ static string_list_t result_pop
 static int substitution_start
   PARAMS ((demangling_t));
 static status_t substitution_add
-  PARAMS ((demangling_t, int, int, int));
+  PARAMS ((demangling_t, int, int));
 static dyn_string_t substitution_get
   PARAMS ((demangling_t, int, int *));
 #ifdef CP_DEMANGLE_DEBUG
@@ -287,6 +287,22 @@ static void demangling_delete
   (dyn_string_append_char (&(DM)->result->string, (CHAR))               \
    ? STATUS_OK : STATUS_ALLOCATION_FAILED)
 
+/* Inserts a dyn_string_t to the demangled result at position POS.  */
+#define result_insert_string(DM, POS, STRING)                           \
+  (dyn_string_insert (&(DM)->result->string, (POS), (STRING))           \
+   ? STATUS_OK : STATUS_ALLOCATION_FAILED)
+
+/* Inserts NUL-terminated string CSTR to the demangled result at
+   position POS.  */
+#define result_insert(DM, POS, CSTR)                                    \
+  (dyn_string_insert_cstr (&(DM)->result->string, (POS), (CSTR))        \
+   ? STATUS_OK : STATUS_ALLOCATION_FAILED)
+
+/* Inserts character CHAR to the demangled result at position POS.  */
+#define result_insert_char(DM, POS, CHAR)                               \
+  (dyn_string_insert_char (&(DM)->result->string, (POS), (CHAR))        \
+   ? STATUS_OK : STATUS_ALLOCATION_FAILED)
+
 /* The length of the current demangled result.  */
 #define result_length(DM)                                               \
   dyn_string_length (&(DM)->result->string)
@@ -297,6 +313,13 @@ static void demangling_delete
   (dyn_string_append_space (&(DM)->result->string)                      \
    ? STATUS_OK : STATUS_ALLOCATION_FAILED)
 
+/* Appends a (less-than, greater-than) character to the result in DM
+   to (open, close) a template argument or parameter list.  Appends a
+   space first if necessary to prevent spurious elision of angle
+   brackets with the previous character.  */
+#define result_open_template_list(DM) result_add_separated_char(DM, '<')
+#define result_close_template_list(DM) result_add_separated_char(DM, '>')
+
 /* Appends a base 10 representation of VALUE to DS.  STATUS_OK on
    success.  On failure, deletes DS and returns an error code.  */
 
@@ -378,28 +401,27 @@ string_list_delete (node)
     }
 }
 
-/* Appends a greater-than character to the demangled result.  If the
-   last character is a greater-than character, a space is inserted
-   first, so that the two greater-than characters don't look like a
-   right shift token.  */
+/* Appends CHARACTER to the demangled result.  If the current trailing
+   character of the result is CHARACTER, a space is inserted first.  */
 
 static status_t
-result_close_template_list (dm)
+result_add_separated_char (dm, character)
      demangling_t dm;
+     int character;
 {
   dyn_string_t s = &dm->result->string;
 
   /* Add a space if the last character is already a closing angle
      bracket, so that a nested template arg list doesn't look like
      it's closed with a right-shift operator.  */
-  if (dyn_string_last_char (s) == '>')
+  if (dyn_string_last_char (s) == character)
     {
       if (!dyn_string_append_char (s, ' '))
        return STATUS_ALLOCATION_FAILED;
     }
 
   /* Add closing angle brackets.  */
-  if (!dyn_string_append_char (s, '>'))
+  if (!dyn_string_append_char (s, character))
     return STATUS_ALLOCATION_FAILED;
 
   return STATUS_OK;
@@ -451,19 +473,13 @@ substitution_start (dm)
 
 /* Adds the suffix of the current demangled result of DM starting at
    START_POSITION as a potential substitution.  If TEMPLATE_P is
-   non-zero, this potential substitution is a template-id.  
-
-   If TEMPLATE_PARM_NUMBER is not NOT_TEMPLATE_PARM, the substitution
-   is for that particular <template-param>, and is distinct from other
-   otherwise-identical types and other <template-param>s with
-   different indices.  */
+   non-zero, this potential substitution is a template-id.  */
 
 static status_t
-substitution_add (dm, start_position, template_p, template_parm_number)
+substitution_add (dm, start_position, template_p)
      demangling_t dm;
      int start_position;
      int template_p;
-     int template_parm_number;
 {
   dyn_string_t result = result_string (dm);
   dyn_string_t substitution = dyn_string_new (0);
@@ -481,23 +497,14 @@ substitution_add (dm, start_position, template_p, template_parm_number)
       return STATUS_ALLOCATION_FAILED;
     }
 
-  /* Check whether SUBSTITUTION already occurs.  */
-  for (i = 0; i < dm->num_substitutions; ++i)
-    if (dyn_string_eq (dm->substitutions[i].text, substitution)
-       && dm->substitutions[i].template_parm_number == template_parm_number)
-      /* Found SUBSTITUTION already present.  */
-      {
-       /* Callers expect this function to take ownership of
-          SUBSTITUTION, so delete it.  */
-       dyn_string_delete (substitution);
-       return STATUS_OK;
-      }
-
   /* If there's no room for the new entry, grow the array.  */
   if (dm->substitutions_allocated == dm->num_substitutions)
     {
       size_t new_array_size;
-      dm->substitutions_allocated *= 2;
+      if (dm->substitutions_allocated > 0)
+       dm->substitutions_allocated *= 2;
+      else
+       dm->substitutions_allocated = 2;
       new_array_size = 
        sizeof (struct substitution_def) * dm->substitutions_allocated;
 
@@ -512,10 +519,9 @@ substitution_add (dm, start_position, template_p, template_parm_number)
     }
 
   /* Add the substitution to the array.  */
+  i = dm->num_substitutions++;
   dm->substitutions[i].text = substitution;
   dm->substitutions[i].template_p = template_p;
-  dm->substitutions[i].template_parm_number = template_parm_number;
-  ++dm->num_substitutions;
 
 #ifdef CP_DEMANGLE_DEBUG
   substitutions_print (dm, stderr);
@@ -801,7 +807,7 @@ static status_t demangle_nested_name
 static status_t demangle_prefix
   PARAMS ((demangling_t, int *));
 static status_t demangle_unqualified_name
-  PARAMS ((demangling_t));
+  PARAMS ((demangling_t, int *));
 static status_t demangle_source_name
   PARAMS ((demangling_t));
 static status_t demangle_number
@@ -812,12 +818,18 @@ static status_t demangle_identifier
   PARAMS ((demangling_t, int, dyn_string_t));
 static status_t demangle_operator_name
   PARAMS ((demangling_t, int, int *));
+static status_t demangle_nv_offset
+  PARAMS ((demangling_t));
+static status_t demangle_v_offset
+  PARAMS ((demangling_t));
+static status_t demangle_call_offset
+  PARAMS ((demangling_t));
 static status_t demangle_special_name
   PARAMS ((demangling_t));
 static status_t demangle_ctor_dtor_name
   PARAMS ((demangling_t));
 static status_t demangle_type_ptr
-  PARAMS ((demangling_t));
+  PARAMS ((demangling_t, int *, int));
 static status_t demangle_type
   PARAMS ((demangling_t));
 static status_t demangle_CV_qualifiers
@@ -825,15 +837,15 @@ static status_t demangle_CV_qualifiers
 static status_t demangle_builtin_type
   PARAMS ((demangling_t));
 static status_t demangle_function_type
-  PARAMS ((demangling_t, int));
+  PARAMS ((demangling_t, int *));
 static status_t demangle_bare_function_type
-  PARAMS ((demangling_t, int));
+  PARAMS ((demangling_t, int *));
 static status_t demangle_class_enum_type
   PARAMS ((demangling_t, int *));
 static status_t demangle_array_type
   PARAMS ((demangling_t));
 static status_t demangle_template_param
-  PARAMS ((demangling_t, int *));
+  PARAMS ((demangling_t));
 static status_t demangle_template_args
   PARAMS ((demangling_t));
 static status_t demangle_literal
@@ -847,19 +859,21 @@ static status_t demangle_scope_expression
 static status_t demangle_expr_primary
   PARAMS ((demangling_t));
 static status_t demangle_substitution
-  PARAMS ((demangling_t, int *, int *));
+  PARAMS ((demangling_t, int *));
 static status_t demangle_local_name
   PARAMS ((demangling_t));
 static status_t demangle_discriminator 
   PARAMS ((demangling_t, int));
 static status_t cp_demangle
   PARAMS ((const char *, dyn_string_t));
+#ifdef IN_LIBGCC2
 static status_t cp_demangle_type
   PARAMS ((const char*, dyn_string_t));
+#endif
 
 /* When passed to demangle_bare_function_type, indicates that the
    function's return type is not encoded before its parameter types.  */
-#define BFT_NO_RETURN_TYPE    -1
+#define BFT_NO_RETURN_TYPE    NULL
 
 /* Check that the next character is C.  If so, consume it.  If not,
    return an error.  */
@@ -910,7 +924,7 @@ static status_t
 demangle_encoding (dm)
      demangling_t dm;
 {
-  int template_p;
+  int encode_return_type;
   int start_position;
   template_arg_list_t old_arg_list = current_template_arg_list (dm);
   char peek = peek_char (dm);
@@ -926,18 +940,18 @@ demangle_encoding (dm)
   else
     {
       /* Now demangle the name.  */
-      RETURN_IF_ERROR (demangle_name (dm, &template_p));
+      RETURN_IF_ERROR (demangle_name (dm, &encode_return_type));
 
       /* If there's anything left, the name was a function name, with
         maybe its return type, and its parameters types, following.  */
       if (!end_of_name_p (dm) 
          && peek_char (dm) != 'E')
        {
-         if (template_p)
+         if (encode_return_type)
            /* Template functions have their return type encoded.  The
               return type should be inserted at start_position.  */
            RETURN_IF_ERROR 
-             (demangle_bare_function_type (dm, start_position));
+             (demangle_bare_function_type (dm, &start_position));
          else
            /* Non-template functions don't have their return type
               encoded.  */
@@ -968,24 +982,32 @@ demangle_encoding (dm)
                         ::= <substitution>  */
 
 static status_t
-demangle_name (dm, template_p)
+demangle_name (dm, encode_return_type)
      demangling_t dm;
-     int *template_p;
+     int *encode_return_type;
 {
-  int special_std_substitution;
   int start = substitution_start (dm);
+  char peek = peek_char (dm);
+  int is_std_substitution = 0;
+
+  /* Generally, the return type is encoded if the function is a
+     template-id, and suppressed otherwise.  There are a few cases,
+     though, in which the return type is not encoded even for a
+     templated function.  In these cases, this flag is set.  */
+  int suppress_return_type = 0;
 
   DEMANGLE_TRACE ("name", dm);
 
-  switch (peek_char (dm))
+  switch (peek)
     {
     case 'N':
       /* This is a <nested-name>.  */
-      RETURN_IF_ERROR (demangle_nested_name (dm, template_p));
+      RETURN_IF_ERROR (demangle_nested_name (dm, encode_return_type));
       break;
 
     case 'Z':
       RETURN_IF_ERROR (demangle_local_name (dm));
+      *encode_return_type = 0;
       break;
 
     case 'S':
@@ -996,48 +1018,45 @@ demangle_name (dm, template_p)
          (void) next_char (dm);
          (void) next_char (dm);
          RETURN_IF_ERROR (result_append (dm, "std::"));
-         RETURN_IF_ERROR (demangle_unqualified_name (dm));
+         RETURN_IF_ERROR 
+           (demangle_unqualified_name (dm, &suppress_return_type));
+         is_std_substitution = 1;
        }
       else
-       {
-         RETURN_IF_ERROR (demangle_substitution (dm, template_p,
-                                                 &special_std_substitution));
-         if (special_std_substitution)
-           {
-             /* This was the magic `std::' substitution.  We can have
-                a <nested-name> or one of the unscoped names
-                following.  */
-             RETURN_IF_ERROR (result_append (dm, "::"));
-             RETURN_IF_ERROR (demangle_name (dm, template_p));
-           }
-       }
+       RETURN_IF_ERROR (demangle_substitution (dm, encode_return_type));
       /* Check if a template argument list immediately follows.
         If so, then we just demangled an <unqualified-template-name>.  */
       if (peek_char (dm) == 'I') 
        {
-         RETURN_IF_ERROR (substitution_add (dm, start, 0, 
-                                            NOT_TEMPLATE_PARM));
+         /* A template name of the form std::<unqualified-name> is a
+             substitution candidate.  */
+         if (is_std_substitution)
+           RETURN_IF_ERROR (substitution_add (dm, start, 0));
+         /* Demangle the <template-args> here.  */
          RETURN_IF_ERROR (demangle_template_args (dm));
+         *encode_return_type = !suppress_return_type;
        }
+      else
+       *encode_return_type = 0;
+
       break;
 
     default:
       /* This is an <unscoped-name> or <unscoped-template-name>.  */
-      RETURN_IF_ERROR (demangle_unqualified_name (dm));
+      RETURN_IF_ERROR (demangle_unqualified_name (dm, &suppress_return_type));
 
       /* If the <unqualified-name> is followed by template args, this
         is an <unscoped-template-name>.  */
       if (peek_char (dm) == 'I')
        {
          /* Add a substitution for the unqualified template name.  */
-         RETURN_IF_ERROR (substitution_add (dm, start, 0, 
-                                            NOT_TEMPLATE_PARM));
+         RETURN_IF_ERROR (substitution_add (dm, start, 0));
 
          RETURN_IF_ERROR (demangle_template_args (dm));
-         *template_p = 1;
+         *encode_return_type = !suppress_return_type;
        }
       else
-       *template_p = 0;
+       *encode_return_type = 0;
 
       break;
     }
@@ -1047,12 +1066,12 @@ demangle_name (dm, template_p)
 
 /* Demangles and emits a <nested-name>. 
 
-    <nested-name>       ::= N [<CV-qualifiers>] <prefix> <component> E  */
+    <nested-name>     ::= N [<CV-qualifiers>] <prefix> <unqulified-name> E  */
 
 static status_t
-demangle_nested_name (dm, template_p)
+demangle_nested_name (dm, encode_return_type)
      demangling_t dm;
-     int *template_p;
+     int *encode_return_type;
 {
   char peek;
 
@@ -1077,9 +1096,9 @@ demangle_nested_name (dm, template_p)
       RETURN_IF_ERROR (result_append_space (dm));
     }
   
-  RETURN_IF_ERROR (demangle_prefix (dm, template_p));
-  /* No need to demangle the final <component>; demangle_prefix will
-     handle it.  */
+  RETURN_IF_ERROR (demangle_prefix (dm, encode_return_type));
+  /* No need to demangle the final <unqualified-name>; demangle_prefix
+     will handle it.  */
   RETURN_IF_ERROR (demangle_char (dm, 'E'));
 
   return STATUS_OK;
@@ -1087,41 +1106,52 @@ demangle_nested_name (dm, template_p)
 
 /* Demangles and emits a <prefix>.
 
-    <prefix>            ::= <prefix> <component>
+    <prefix>            ::= <prefix> <unqualified-name>
                         ::= <template-prefix> <template-args>
                        ::= # empty
                        ::= <substitution>
 
     <template-prefix>   ::= <prefix>
-                        ::= <substitution>
-
-    <component>         ::= <unqualified-name>
-                        ::= <local-name>  */
+                        ::= <substitution>  */
 
 static status_t
-demangle_prefix (dm, template_p)
+demangle_prefix (dm, encode_return_type)
      demangling_t dm;
-     int *template_p;
+     int *encode_return_type;
 {
   int start = substitution_start (dm);
   int nested = 0;
 
-  /* TEMPLATE_P is updated as we decend the nesting chain.  After
-     <template-args>, it is set to non-zero; after everything else it
-     is set to zero.  */
+  /* ENCODE_RETURN_TYPE is updated as we decend the nesting chain.
+     After <template-args>, it is set to non-zero; after everything
+     else it is set to zero.  */
+
+  /* Generally, the return type is encoded if the function is a
+     template-id, and suppressed otherwise.  There are a few cases,
+     though, in which the return type is not encoded even for a
+     templated function.  In these cases, this flag is set.  */
+  int suppress_return_type = 0;
 
   DEMANGLE_TRACE ("prefix", dm);
 
   while (1)
     {
       char peek;
-      int unused;
 
       if (end_of_name_p (dm))
        return "Unexpected end of name in <compound-name>.";
 
       peek = peek_char (dm);
       
+      /* We'll initialize suppress_return_type to false, and set it to true
+        if we end up demangling a constructor name.  However, make
+        sure we're not actually about to demangle template arguments
+        -- if so, this is the <template-args> following a
+        <template-prefix>, so we'll want the previous flag value
+        around.  */
+      if (peek != 'I')
+       suppress_return_type = 0;
+
       if (IS_DIGIT ((unsigned char) peek)
          || (peek >= 'a' && peek <= 'z')
          || peek == 'C' || peek == 'D'
@@ -1135,25 +1165,30 @@ demangle_prefix (dm, template_p)
 
          if (peek == 'S')
            /* The substitution determines whether this is a
-              template-id.   */
-           RETURN_IF_ERROR (demangle_substitution (dm, template_p, 
-                                                   &unused));
+              template-id.  */
+           RETURN_IF_ERROR (demangle_substitution (dm, encode_return_type));
          else
            {
-             RETURN_IF_ERROR (demangle_unqualified_name (dm));
-             *template_p = 0;
+             /* It's just a name.  */
+             RETURN_IF_ERROR 
+               (demangle_unqualified_name (dm, &suppress_return_type));
+             *encode_return_type = 0;
            }
        }
       else if (peek == 'Z')
        RETURN_IF_ERROR (demangle_local_name (dm));
       else if (peek == 'I')
        {
-         if (*template_p)
-           return STATUS_INTERNAL_ERROR;
-         /* The template name is a substitution candidate.  */
-         RETURN_IF_ERROR (substitution_add (dm, start, 0, NOT_TEMPLATE_PARM));
          RETURN_IF_ERROR (demangle_template_args (dm));
-         *template_p = 1;
+
+         /* Now we want to indicate to the caller that we've
+            demangled template arguments, thus the prefix was a
+            <template-prefix>.  That's so that the caller knows to
+            demangle the function's return type, if this turns out to
+            be a function name.  But, if it's a member template
+            constructor or a templated conversion operator, report it
+            as untemplated.  Those never get encoded return types.  */
+         *encode_return_type = !suppress_return_type;
        }
       else if (peek == 'E')
        /* All done.  */
@@ -1161,38 +1196,56 @@ demangle_prefix (dm, template_p)
       else
        return "Unexpected character in <compound-name>.";
 
-      /* Add a new substitution for the prefix thus far.  */
-      RETURN_IF_ERROR (substitution_add (dm, start, *template_p, 
-                                        NOT_TEMPLATE_PARM));
+      if (peek != 'S'
+         && peek_char (dm) != 'E')
+       /* Add a new substitution for the prefix thus far.  */
+       RETURN_IF_ERROR (substitution_add (dm, start, *encode_return_type));
     }
 }
 
-/* Demangles and emits an <unqualified-name>.  If the
-   <unqualified-name> is a function and the first element in the
-   argument list should be taken to be its return type,
-   ENCODE_RETURN_TYPE is non-zero.
+/* Demangles and emits an <unqualified-name>.  If this
+   <unqualified-name> is for a special function type that should never
+   have its return type encoded (particularly, a constructor or
+   conversion operator), *SUPPRESS_RETURN_TYPE is set to 1; otherwise,
+   it is set to zero.
 
     <unqualified-name>  ::= <operator-name>
                        ::= <special-name>  
                        ::= <source-name>  */
 
 static status_t
-demangle_unqualified_name (dm)
+demangle_unqualified_name (dm, suppress_return_type)
      demangling_t dm;
+     int *suppress_return_type;
 {
   char peek = peek_char (dm);
 
   DEMANGLE_TRACE ("unqualified-name", dm);
 
+  /* By default, don't force suppression of the return type (though
+     non-template functions still don't get a return type encoded).  */ 
+  *suppress_return_type = 0;
+
   if (IS_DIGIT ((unsigned char) peek))
     RETURN_IF_ERROR (demangle_source_name (dm));
   else if (peek >= 'a' && peek <= 'z')
     {
       int num_args;
+
+      /* Conversion operators never have a return type encoded.  */
+      if (peek == 'c' && peek_char_next (dm) == 'v')
+       *suppress_return_type = 1;
+
       RETURN_IF_ERROR (demangle_operator_name (dm, 0, &num_args));
     }
   else if (peek == 'C' || peek == 'D')
-    RETURN_IF_ERROR (demangle_ctor_dtor_name (dm));
+    {
+      /* Constructors never have a return type encoded.  */
+      if (peek == 'C')
+       *suppress_return_type = 1;
+
+      RETURN_IF_ERROR (demangle_ctor_dtor_name (dm));
+    }
   else
     return "Unexpected character in <unqualified-name>.";
 
@@ -1330,6 +1383,29 @@ demangle_identifier (dm, length, identifier)
        return STATUS_ALLOCATION_FAILED;
     }
 
+  /* GCC encodes anonymous namespaces using a `_GLOBAL_[_.$]N.'
+     followed by the source file name and some random characters.
+     Unless we're in strict mode, decipher these names appropriately.  */
+  if (!flag_strict)
+    {
+      char *name = dyn_string_buf (identifier);
+      int prefix_length = strlen (ANONYMOUS_NAMESPACE_PREFIX);
+
+      /* Compare the first, fixed part.  */
+      if (strncmp (name, ANONYMOUS_NAMESPACE_PREFIX, prefix_length) == 0)
+        {
+         name += prefix_length;
+         /* The next character might be a period, an underscore, or
+            dollar sign, depending on the target architecture's
+            assembler's capabilities.  After that comes an `N'.  */
+         if ((*name == '.' || *name == '_' || *name == '$')
+             && *(name + 1) == 'N')
+           /* This looks like the anonymous namespace identifier.
+              Replace it with something comprehensible.  */
+           dyn_string_copy_cstr (identifier, "(anonymous namespace)");
+       }
+    }
+
   return STATUS_OK;
 }
 
@@ -1388,7 +1464,7 @@ demangle_identifier (dm, length, identifier)
                   ::= qu        # ?
                   ::= sz        # sizeof 
                   ::= cv <type> # cast        
-                  ::= vx <source-name>  # vendor extended operator  */
+                 ::= v [0-9] <source-name>  # vendor extended operator  */
 
 static status_t
 demangle_operator_name (dm, short_name, num_args)
@@ -1449,6 +1525,7 @@ demangle_operator_name (dm, short_name, num_args)
     { "pm", "->*"      , 2 },
     { "pp", "++"       , 1 },
     { "ps", "+"        , 1 },
+    { "pt", "->"       , 2 },
     { "qu", "?"        , 3 },
     { "rM", "%="       , 2 },
     { "rS", ">>="      , 2 },
@@ -1467,10 +1544,10 @@ demangle_operator_name (dm, short_name, num_args)
 
   DEMANGLE_TRACE ("operator-name", dm);
 
-  /* Is this a vendor extended operator?  */
-  if (c0 == 'v' && c1 == 'x')
+  /* Is this a vendor-extended operator?  */
+  if (c0 == 'v' && IS_DIGIT (c1))
     {
-      RETURN_IF_ERROR (result_append (dm, "operator"));
+      RETURN_IF_ERROR (result_append (dm, "operator "));
       RETURN_IF_ERROR (demangle_source_name (dm));
       *num_args = 0;
       return STATUS_OK;
@@ -1516,22 +1593,157 @@ demangle_operator_name (dm, short_name, num_args)
     }
 }
 
+/* Demangles and omits an <nv-offset>.
+
+    <nv-offset> ::= <offset number>   # non-virtual base override  */
+
+static status_t
+demangle_nv_offset (dm)
+     demangling_t dm;
+{
+  dyn_string_t number;
+  status_t status = STATUS_OK;
+
+  DEMANGLE_TRACE ("h-offset", dm);
+
+  /* Demangle the offset.  */
+  number = dyn_string_new (4);
+  if (number == NULL)
+    return STATUS_ALLOCATION_FAILED;
+  demangle_number_literally (dm, number, 10, 1);
+
+  /* Don't display the offset unless in verbose mode.  */
+  if (flag_verbose)
+    {
+      status = result_append (dm, " [nv:");
+      if (STATUS_NO_ERROR (status))
+       status = result_append_string (dm, number);
+      if (STATUS_NO_ERROR (status))
+       status = result_append_char (dm, ']');
+    }
+
+  /* Clean up.  */
+  dyn_string_delete (number);
+  RETURN_IF_ERROR (status);
+  return STATUS_OK;
+}
+
+/* Demangles and emits a <v-offset>. 
+
+    <v-offset>  ::= <offset number> _ <virtual offset number>
+                       # virtual base override, with vcall offset  */
+
+static status_t
+demangle_v_offset (dm)
+     demangling_t dm;
+{
+  dyn_string_t number;
+  status_t status = STATUS_OK;
+
+  DEMANGLE_TRACE ("v-offset", dm);
+
+  /* Demangle the offset.  */
+  number = dyn_string_new (4);
+  if (number == NULL)
+    return STATUS_ALLOCATION_FAILED;
+  demangle_number_literally (dm, number, 10, 1);
+
+  /* Don't display the offset unless in verbose mode.  */
+  if (flag_verbose)
+    {
+      status = result_append (dm, " [v:");
+      if (STATUS_NO_ERROR (status))
+       status = result_append_string (dm, number);
+      if (STATUS_NO_ERROR (status))
+       result_append_char (dm, ',');
+    }
+  dyn_string_delete (number);
+  RETURN_IF_ERROR (status);
+
+  /* Demangle the separator.  */
+  RETURN_IF_ERROR (demangle_char (dm, '_'));
+
+  /* Demangle the vcall offset.  */
+  number = dyn_string_new (4);
+  if (number == NULL)
+    return STATUS_ALLOCATION_FAILED;
+  demangle_number_literally (dm, number, 10, 1);
+
+  /* Don't display the vcall offset unless in verbose mode.  */
+  if (flag_verbose)
+    {
+      status = result_append_string (dm, number);
+      if (STATUS_NO_ERROR (status))
+       status = result_append_char (dm, ']');
+    }
+  dyn_string_delete (number);
+  RETURN_IF_ERROR (status);
+
+  return STATUS_OK;
+}
+
+/* Demangles and emits a <call-offset>.
+
+    <call-offset> ::= h <nv-offset> _
+                 ::= v <v-offset> _  */
+
+static status_t
+demangle_call_offset (dm)
+     demangling_t dm;
+{
+  DEMANGLE_TRACE ("call-offset", dm);
+
+  switch (peek_char (dm))
+    {
+    case 'h':
+      advance_char (dm);
+      /* Demangle the offset.  */
+      RETURN_IF_ERROR (demangle_nv_offset (dm));
+      /* Demangle the separator.  */
+      RETURN_IF_ERROR (demangle_char (dm, '_'));
+      break;
+
+    case 'v':
+      advance_char (dm);
+      /* Demangle the offset.  */
+      RETURN_IF_ERROR (demangle_v_offset (dm));
+      /* Demangle the separator.  */
+      RETURN_IF_ERROR (demangle_char (dm, '_'));
+      break;
+
+    default:
+      return "Unrecognized <call-offset>.";
+    }
+
+  return STATUS_OK;
+}
+
 /* Demangles and emits a <special-name>.  
 
     <special-name> ::= GV <object name>   # Guard variable
-                   ::= Th[n] <offset number> _ <base name> <base encoding>
-                                          # non-virtual base override thunk
-                   ::= Tv[n] <offset number> _ <vcall offset number> 
-                         _ <base encoding>
-                                          # virtual base override thunk
                    ::= TV <type>          # virtual table
                    ::= TT <type>          # VTT
                    ::= TI <type>          # typeinfo structure
                   ::= TS <type>          # typeinfo name  
 
+   Other relevant productions include thunks:
+
+    <special-name> ::= T <call-offset> <base encoding>
+                        # base is the nominal target function of thunk
+
+    <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+                        # base is the nominal target function of thunk
+                        # first call-offset is 'this' adjustment
+                        # second call-offset is result adjustment
+
+   where
+
+    <call-offset>  ::= h <nv-offset> _
+                  ::= v <v-offset> _
+
    Also demangles the special g++ manglings,
 
-    <special-name> ::= CT <type> <offset number> _ <base type>
+    <special-name> ::= TC <type> <offset number> _ <base type>
                                           # construction vtable
                   ::= TF <type>          # typeinfo function (old ABI only)
                   ::= TJ <type>          # java Class structure  */
@@ -1609,20 +1821,7 @@ demangle_special_name (dm)
          /* Non-virtual thunk.  */
          advance_char (dm);
          RETURN_IF_ERROR (result_append (dm, "non-virtual thunk"));
-         /* Demangle and emit the offset.  */
-         number = dyn_string_new (4);
-         if (number == NULL)
-           return STATUS_ALLOCATION_FAILED;
-         demangle_number_literally (dm, number, 10, 1);
-         /* Don't display the offset unless in verbose mode.  */
-         if (flag_verbose)
-           {
-             status = result_append_char (dm, ' ');
-             if (STATUS_NO_ERROR (status))
-               status = result_append_string (dm, number);
-           }
-         dyn_string_delete (number);
-         RETURN_IF_ERROR (status);
+         RETURN_IF_ERROR (demangle_nv_offset (dm));
          /* Demangle the separator.  */
          RETURN_IF_ERROR (demangle_char (dm, '_'));
          /* Demangle and emit the target name and function type.  */
@@ -1633,41 +1832,23 @@ demangle_special_name (dm)
        case 'v':
          /* Virtual thunk.  */
          advance_char (dm);
-         RETURN_IF_ERROR (result_append (dm, "virtual thunk "));
-         /* Demangle and emit the offset.  */
-         number = dyn_string_new (4);
-         if (number == NULL)
-           return STATUS_ALLOCATION_FAILED;
-         demangle_number_literally (dm, number, 10, 1);
-         /* Don't display the offset unless in verbose mode.  */
-         if (flag_verbose)
-           {
-             status = result_append_string (dm, number);
-             if (STATUS_NO_ERROR (status))
-               result_append_char (dm, ' ');
-           }
-         dyn_string_delete (number);
-         RETURN_IF_ERROR (status);
-         /* Demangle the separator.  */
-         RETURN_IF_ERROR (demangle_char (dm, '_'));
-         /* Demangle and emit the vcall offset.  */
-         number = dyn_string_new (4);
-         if (number == NULL)
-           return STATUS_ALLOCATION_FAILED;
-         demangle_number_literally (dm, number, 10, 1);
-         /* Don't display the vcall offset unless in verbose mode.  */
-         if (flag_verbose)
-           {
-             status = result_append_string (dm, number);
-             if (STATUS_NO_ERROR (status))
-               status = result_append_char (dm, ' ');
-           }
-         dyn_string_delete (number);
-         RETURN_IF_ERROR (status);
+         RETURN_IF_ERROR (result_append (dm, "virtual thunk"));
+         RETURN_IF_ERROR (demangle_v_offset (dm));
          /* Demangle the separator.  */
          RETURN_IF_ERROR (demangle_char (dm, '_'));
          /* Demangle and emit the target function.  */
-         RETURN_IF_ERROR (result_append (dm, "to "));
+         RETURN_IF_ERROR (result_append (dm, " to "));
+         RETURN_IF_ERROR (demangle_encoding (dm));
+         break;
+
+       case 'c':
+         /* Covariant return thunk.  */
+         advance_char (dm);
+         RETURN_IF_ERROR (result_append (dm, "covariant return thunk"));
+         RETURN_IF_ERROR (demangle_call_offset (dm));
+         RETURN_IF_ERROR (demangle_call_offset (dm));
+         /* Demangle and emit the target function.  */
+         RETURN_IF_ERROR (result_append (dm, " to "));
          RETURN_IF_ERROR (demangle_encoding (dm));
          break;
 
@@ -1736,7 +1917,6 @@ demangle_special_name (dm)
                    ::= C1  # complete object (in-charge) ctor
                    ::= C2  # base object (not-in-charge) ctor
                    ::= C3  # complete object (in-charge) allocating ctor
-                   ::= C4  # base object (not-in-charge) allocating ctor
                    ::= D0  # deleting (in-charge) dtor
                    ::= D1  # complete object (in-charge) dtor
                    ::= D2  # base object (not-in-charge) dtor  */
@@ -1749,8 +1929,7 @@ demangle_ctor_dtor_name (dm)
   {
     "in-charge",
     "not-in-charge",
-    "in-charge allocating",
-    "not-in-charge allocating"
+    "allocating"
   };
   static const char *const dtor_flavors[] = 
   {
@@ -1768,7 +1947,7 @@ demangle_ctor_dtor_name (dm)
     {
       /* A constructor name.  Consume the C.  */
       advance_char (dm);
-      if (peek_char (dm) < '1' || peek_char (dm) > '4')
+      if (peek_char (dm) < '1' || peek_char (dm) > '3')
        return "Unrecognized constructor.";
       RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
       /* Print the flavor of the constructor if in verbose mode.  */
@@ -1810,6 +1989,19 @@ demangle_ctor_dtor_name (dm)
    a pointer to data or pointer to function to construct the right
    output syntax.  C++'s pointer syntax is hairy.  
 
+   This function adds substitution candidates for every nested
+   pointer/reference type it processes, including the outermost, final
+   type, assuming the substitution starts at SUBSTITUTION_START in the
+   demangling result.  For example, if this function demangles
+   `PP3Foo', it will add a substitution for `Foo', `Foo*', and
+   `Foo**', in that order.
+
+   *INSERT_POS is a quantity used internally, when this function calls
+   itself recursively, to figure out where to insert pointer
+   punctuation on the way up.  On entry to this function, INSERT_POS
+   should point to a temporary value, but that value need not be
+   initialized.
+
      <type> ::= P <type>
             ::= R <type>
             ::= <pointer-to-member-type>
@@ -1817,105 +2009,137 @@ demangle_ctor_dtor_name (dm)
      <pointer-to-member-type> ::= M </class/ type> </member/ type>  */
 
 static status_t
-demangle_type_ptr (dm)
+demangle_type_ptr (dm, insert_pos, substitution_start)
      demangling_t dm;
+     int *insert_pos;
+     int substitution_start;
 {
   char next;
   status_t status;
-
-  /* Collect pointer symbols into this string.  */
-  dyn_string_t symbols = dyn_string_new (10);
+  int is_substitution_candidate = 1;
 
   DEMANGLE_TRACE ("type*", dm);
 
-  if (symbols == NULL)
-    return STATUS_ALLOCATION_FAILED;
-
   /* Scan forward, collecting pointers and references into symbols,
      until we hit something else.  Then emit the type.  */
-  while (1)
+  next = peek_char (dm);
+  if (next == 'P')
     {
-      next = peek_char (dm);
-      if (next == 'P')
-       {
-         if (!dyn_string_append_char (symbols, '*'))
-           return STATUS_ALLOCATION_FAILED;
-         advance_char (dm);
-       }
-      else if (next == 'R')
-       {
-         if (!dyn_string_append_char (symbols, '&'))
-           return STATUS_ALLOCATION_FAILED;
-         advance_char (dm);
-       }
-      else if (next == 'M')
-       {
-         /* Pointer-to-member.  */
-         dyn_string_t class_type;
-
-         /* Eat the 'M'.  */
-         advance_char (dm);
-
-         /* Capture the type of which this is a pointer-to-member.  */
-         RETURN_IF_ERROR (result_push (dm));
-         RETURN_IF_ERROR (demangle_type (dm));
-         class_type = (dyn_string_t) result_pop (dm);
-
-         /* Build the pointer-to-member notation.  It comes before
-            other pointer and reference qualifiers -- */
-         if (!dyn_string_prepend_cstr (symbols, "::*"))
-           return STATUS_ALLOCATION_FAILED;
-         if (!dyn_string_prepend (symbols, class_type))
-           return STATUS_ALLOCATION_FAILED;
-         dyn_string_delete (class_type);
-
-         if (peek_char (dm) == 'F')
-           continue;
-
-         /* Demangle the type of the pointed-to member.  */
+      /* A pointer.  Snarf the `P'.  */
+      advance_char (dm);
+      /* Demangle the underlying type.  */
+      RETURN_IF_ERROR (demangle_type_ptr (dm, insert_pos, 
+                                         substitution_start));
+      /* Insert an asterisk where we're told to; it doesn't
+        necessarily go at the end.  */
+      RETURN_IF_ERROR (result_insert_char (dm, *insert_pos, '*'));
+      /* The next (outermost) pointer or reference character should go
+        after this one.  */
+      ++(*insert_pos);
+    }
+  else if (next == 'R')
+    {
+      /* A reference.  Snarf the `R'.  */
+      advance_char (dm);
+      /* Demangle the underlying type.  */
+      RETURN_IF_ERROR (demangle_type_ptr (dm, insert_pos, 
+                                         substitution_start));
+      /* Insert an ampersand where we're told to; it doesn't
+        necessarily go at the end.  */
+      RETURN_IF_ERROR (result_insert_char (dm, *insert_pos, '&'));
+      /* The next (outermost) pointer or reference character should go
+        after this one.  */
+      ++(*insert_pos);
+    }
+  else if (next == 'M')
+    {
+      /* A pointer-to-member.  */
+      dyn_string_t class_type;
+      
+      /* Eat the 'M'.  */
+      advance_char (dm);
+      
+      /* Capture the type of which this is a pointer-to-member.  */
+      RETURN_IF_ERROR (result_push (dm));
+      RETURN_IF_ERROR (demangle_type (dm));
+      class_type = (dyn_string_t) result_pop (dm);
+      
+      if (peek_char (dm) == 'F')
+       /* A pointer-to-member function.  We want output along the
+          lines of `void (C::*) (int, int)'.  Demangle the function
+          type, which would in this case give `void () (int, int)'
+          and set *insert_pos to the spot between the first
+          parentheses.  */
+       status = demangle_type_ptr (dm, insert_pos, substitution_start);
+      else
+        {
+         /* A pointer-to-member variable.  Demangle the type of the
+             pointed-to member.  */
          status = demangle_type (dm);
          /* Make it pretty.  */
          if (STATUS_NO_ERROR (status))
            status = result_append_space (dm);
-         /* Add the pointer-to-member syntax, and other pointer and
-            reference symbols.  */
-         if (STATUS_NO_ERROR (status))
-           status = result_append_string (dm, symbols);
-         /* Clean up.  */
-         dyn_string_delete (symbols);
-
-         RETURN_IF_ERROR (status);
-         return STATUS_OK;
+         /* The pointer-to-member notation (e.g. `C::*') follows the
+             member's type.  */
+         *insert_pos = result_length (dm);
        }
-      else if (next == 'F')
-       {
-         /* Ooh, tricky, a pointer-to-function.  */
-         int position = result_length (dm);
-         status = result_append_char (dm, '(');
-         if (STATUS_NO_ERROR (status))
-           status = result_append_string (dm, symbols);
-         if (STATUS_NO_ERROR (status))
-           status = result_append_char (dm, ')');
-         dyn_string_delete (symbols);
-         RETURN_IF_ERROR (status);
 
-         RETURN_IF_ERROR (demangle_function_type (dm, position));
-         return STATUS_OK;
-       }
-      else
-       {
-         /* No more pointe or reference tokens.  Finish up.  */
-         status = demangle_type (dm);
+      /* Build the pointer-to-member notation.  */
+      if (STATUS_NO_ERROR (status))
+       status = result_insert (dm, *insert_pos, "::*");
+      if (STATUS_NO_ERROR (status))
+       status = result_insert_string (dm, *insert_pos, class_type);
+      /* There may be additional levels of (pointer or reference)
+        indirection in this type.  If so, the `*' and `&' should be
+        added after the pointer-to-member notation (e.g. `C::*&' for
+        a reference to a pointer-to-member of class C).  */
+      *insert_pos += dyn_string_length (class_type) + 3;
 
-         if (STATUS_NO_ERROR (status))
-           status = result_append_string (dm, symbols);
-         dyn_string_delete (symbols);
-         RETURN_IF_ERROR (status);
+      /* Clean up. */
+      dyn_string_delete (class_type);
 
-         RETURN_IF_ERROR (status);
-         return STATUS_OK;
-       }
+      RETURN_IF_ERROR (status);
+    }
+  else if (next == 'F')
+    {
+      /* Ooh, tricky, a pointer-to-function.  When we demangle the
+        function type, the return type should go at the very
+        beginning.  */
+      *insert_pos = result_length (dm);
+      /* The parentheses indicate this is a function pointer or
+        reference type.  */
+      RETURN_IF_ERROR (result_append (dm, "()"));
+      /* Now demangle the function type.  The return type will be
+        inserted before the `()', and the argument list will go after
+        it.  */
+      RETURN_IF_ERROR (demangle_function_type (dm, insert_pos));
+      /* We should now have something along the lines of 
+        `void () (int, int)'.  The pointer or reference characters
+        have to inside the first set of parentheses.  *insert_pos has
+        already been updated to point past the end of the return
+        type.  Move it one character over so it points inside the
+        `()'.  */
+      ++(*insert_pos);
+    }
+  else
+    {
+      /* No more pointer or reference tokens; this is therefore a
+        pointer to data.  Finish up by demangling the underlying
+        type.  */
+      RETURN_IF_ERROR (demangle_type (dm));
+      /* The pointer or reference characters follow the underlying
+        type, as in `int*&'.  */
+      *insert_pos = result_length (dm);
+      /* Because of the production <type> ::= <substitution>,
+        demangle_type will already have added the underlying type as
+        a substitution candidate.  Don't do it again.  */
+      is_substitution_candidate = 0;
     }
+  
+  if (is_substitution_candidate)
+    RETURN_IF_ERROR (substitution_add (dm, substitution_start, 0));
+  
+  return STATUS_OK;
 }
 
 /* Demangles and emits a <type>.  
@@ -1926,6 +2150,7 @@ demangle_type_ptr (dm)
           ::= <array-type>
           ::= <pointer-to-member-type>
           ::= <template-param>
+          ::= <template-template-param> <template-args>
            ::= <CV-qualifiers> <type>
           ::= P <type>   # pointer-to
           ::= R <type>   # reference-to
@@ -1941,22 +2166,28 @@ demangle_type (dm)
   int start = substitution_start (dm);
   char peek = peek_char (dm);
   char peek_next;
-  int template_p = 0;
-  int special_std_substitution;
-  int is_builtin_type = 0;
+  int encode_return_type = 0;
   template_arg_list_t old_arg_list = current_template_arg_list (dm);
-  int template_parm = NOT_TEMPLATE_PARM;
+  int insert_pos;
+
+  /* A <type> can be a <substitution>; therefore, this <type> is a
+     substitution candidate unless a special condition holds (see
+     below).  */
+  int is_substitution_candidate = 1;
 
   DEMANGLE_TRACE ("type", dm);
 
   /* A <class-enum-type> can start with a digit (a <source-name>), an
      N (a <nested-name>), or a Z (a <local-name>).  */
   if (IS_DIGIT ((unsigned char) peek) || peek == 'N' || peek == 'Z')
-    RETURN_IF_ERROR (demangle_class_enum_type (dm, &template_p));
-  else if (peek >= 'a' && peek <= 'z')
+    RETURN_IF_ERROR (demangle_class_enum_type (dm, &encode_return_type));
+  /* Lower-case letters begin <builtin-type>s, except for `r', which
+     denotes restrict.  */
+  else if (peek >= 'a' && peek <= 'z' && peek != 'r')
     {
       RETURN_IF_ERROR (demangle_builtin_type (dm));
-      is_builtin_type = 1;
+      /* Built-in types are not substitution candidates.  */
+      is_substitution_candidate = 0;
     }
   else
     switch (peek)
@@ -1964,6 +2195,9 @@ demangle_type (dm)
       case 'r':
       case 'V':
       case 'K':
+       /* CV-qualifiers (including restrict).  We have to demangle
+          them off to the side, since C++ syntax puts them in a funny
+          place for qualified pointer and reference types.  */
        {
          status_t status;
          dyn_string_t cv_qualifiers = dyn_string_new (24);
@@ -2006,7 +2240,28 @@ demangle_type (dm)
        break;
 
       case 'T':
-       RETURN_IF_ERROR (demangle_template_param (dm, &template_parm));
+       /* It's either a <template-param> or a
+          <template-template-param>.  In either case, demangle the
+          `T' token first.  */
+       RETURN_IF_ERROR (demangle_template_param (dm));
+
+       /* Check for a template argument list; if one is found, it's a
+            <template-template-param> ::= <template-param>
+                                       ::= <substitution>  */
+       if (peek_char (dm) == 'I')
+         {
+           /* Add a substitution candidate.  The template parameter
+              `T' token is a substitution candidate by itself,
+              without the template argument list.  */
+           RETURN_IF_ERROR (substitution_add (dm, start, encode_return_type));
+
+           /* Now demangle the template argument list.  */
+           RETURN_IF_ERROR (demangle_template_args (dm));
+           /* The entire type, including the template template
+              parameter and its argument list, will be added as a
+              substitution candidate below.  */
+         }
+
        break;
 
       case 'S':
@@ -2016,16 +2271,56 @@ demangle_type (dm)
           or underscore.  */
        peek_next = peek_char_next (dm);
        if (IS_DIGIT (peek_next) || peek_next == '_')
-         RETURN_IF_ERROR (demangle_substitution (dm, &template_p,
-                                                 &special_std_substitution));
+         {
+           RETURN_IF_ERROR (demangle_substitution (dm, &encode_return_type));
+           
+           /* The substituted name may have been a template name.
+              Check if template arguments follow, and if so, demangle
+              them.  */
+           if (peek_char (dm) == 'I')
+             RETURN_IF_ERROR (demangle_template_args (dm));
+           else
+             /* A substitution token is not itself a substitution
+                candidate.  (However, if the substituted template is
+                instantiated, the resulting type is.)  */
+             is_substitution_candidate = 0;
+         }
        else
-         demangle_class_enum_type (dm, &template_p);
+         {
+           /* Now some trickiness.  We have a special substitution
+              here.  Often, the special substitution provides the
+              name of a template that's subsequently instantiated,
+              for instance `SaIcE' => std::allocator<char>.  In these
+              cases we need to add a substitution candidate for the
+              entire <class-enum-type> and thus don't want to clear
+              the is_substitution_candidate flag.
+
+              However, it's possible that what we have here is a
+              substitution token representing an entire type, such as
+              `Ss' => std::string.  In this case, we mustn't add a
+              new substitution candidate for this substitution token.
+              To detect this case, remember where the start of the
+              substitution token is.  */
+           const char *next = dm->next;
+           /* Now demangle the <class-enum-type>.  */
+           RETURN_IF_ERROR 
+             (demangle_class_enum_type (dm, &encode_return_type));
+           /* If all that was just demangled is the two-character
+              special substitution token, supress the addition of a
+              new candidate for it.  */
+           if (dm->next == next + 2)
+             is_substitution_candidate = 0;
+         }
+
        break;
 
       case 'P':
       case 'R':
       case 'M':
-       RETURN_IF_ERROR (demangle_type_ptr (dm));
+       RETURN_IF_ERROR (demangle_type_ptr (dm, &insert_pos, start));
+       /* demangle_type_ptr adds all applicable substitution
+          candidates.  */
+       is_substitution_candidate = 0;
        break;
 
       case 'C':
@@ -2043,7 +2338,7 @@ demangle_type (dm)
        break;
 
       case 'U':
-       /* Vendor extended type qualifier.  */
+       /* Vendor-extended type qualifier.  */
        advance_char (dm);
        RETURN_IF_ERROR (demangle_source_name (dm));
        RETURN_IF_ERROR (result_append_char (dm, ' '));
@@ -2054,13 +2349,12 @@ demangle_type (dm)
        return "Unexpected character in <type>.";
       }
 
-  /* Unqualified builin types are not substitution candidates.  */
-  if (!is_builtin_type)
+  if (is_substitution_candidate)
     /* Add a new substitution for the type. If this type was a
        <template-param>, pass its index since from the point of
-       substitutions, a <template-param> token is a substitution
+       substitutions; a <template-param> token is a substitution
        candidate distinct from the type that is substituted for it.  */
-    RETURN_IF_ERROR (substitution_add (dm, start, template_p, template_parm));
+    RETURN_IF_ERROR (substitution_add (dm, start, encode_return_type));
 
   /* Pop off template argument lists added during mangling of this
      type.  */
@@ -2199,16 +2493,18 @@ demangle_CV_qualifiers (dm, qualifiers)
     }
 }
 
-/* Demangles and emits a <function-type> FUNCTION_NAME_POS is the
+/* Demangles and emits a <function-type>.  *FUNCTION_NAME_POS is the
    position in the result string of the start of the function
-   identifier, at which the function's return type will be inserted.  
+   identifier, at which the function's return type will be inserted;
+   *FUNCTION_NAME_POS is updated to position past the end of the
+   function's return type.
 
     <function-type> ::= F [Y] <bare-function-type> E  */
 
 static status_t
 demangle_function_type (dm, function_name_pos)
      demangling_t dm;
-     int function_name_pos;
+     int *function_name_pos;
 {
   DEMANGLE_TRACE ("function-type", dm);
   RETURN_IF_ERROR (demangle_char (dm, 'F'));  
@@ -2234,7 +2530,7 @@ demangle_function_type (dm, function_name_pos)
 static status_t
 demangle_bare_function_type (dm, return_type_pos)
      demangling_t dm;
-     int return_type_pos;
+     int *return_type_pos;
 {
   /* Sequence is the index of the current function parameter, counting
      from zero.  The value -1 denotes the return type.  */
@@ -2259,10 +2555,16 @@ demangle_bare_function_type (dm, return_type_pos)
 
          /* Add a space to the end of the type.  Insert the return
              type where we've been asked to. */
-         if (!dyn_string_append_space (return_type) 
-             || !dyn_string_insert (result_string (dm), return_type_pos, 
-                                    return_type))
+         if (!dyn_string_append_space (return_type))
            status = STATUS_ALLOCATION_FAILED;
+         if (STATUS_NO_ERROR (status))
+           {
+             if (!dyn_string_insert (result_string (dm), *return_type_pos, 
+                                     return_type))
+               status = STATUS_ALLOCATION_FAILED;
+             else
+               *return_type_pos += dyn_string_length (return_type);
+           }
 
          dyn_string_delete (return_type);
          RETURN_IF_ERROR (status);
@@ -2273,60 +2575,88 @@ demangle_bare_function_type (dm, return_type_pos)
             the only type in a parameter list; in that case, we want
             to print `foo ()' instead of `foo (void)'.  */
          if (peek_char (dm) == 'v')
+           /* Consume the v.  */
+           advance_char (dm);
+         else
            {
-             /* Consume the v.  */
-             advance_char (dm);
-             continue;
+             /* Separate parameter types by commas.  */
+             if (sequence > 0)
+               RETURN_IF_ERROR (result_append (dm, ", "));
+             /* Demangle the type.  */
+             RETURN_IF_ERROR (demangle_type (dm));
            }
-         /* Separate parameter types by commas.  */
-         if (sequence > 0)
-           RETURN_IF_ERROR (result_append (dm, ", "));
-         /* Demangle the type.  */
-         RETURN_IF_ERROR (demangle_type (dm));
        }
 
       ++sequence;
     }
   RETURN_IF_ERROR (result_append_char (dm, ')'));
 
+  /* We should have demangled at least one parameter type (which would
+     be void, for a function that takes no parameters), plus the
+     return type, if we were supposed to demangle that.  */
+  if (sequence == -1)
+    return "Missing function return type.";
+  else if (sequence == 0)
+    return "Missing function parameter.";
+
   return STATUS_OK;
 }
 
-/* Demangles and emits a <class-enum-type>.  *TEMPLATE_P is set to
+/* Demangles and emits a <class-enum-type>.  *ENCODE_RETURN_TYPE is set to
    non-zero if the type is a template-id, zero otherwise.  
 
     <class-enum-type> ::= <name>  */
 
 static status_t
-demangle_class_enum_type (dm, template_p)
+demangle_class_enum_type (dm, encode_return_type)
      demangling_t dm;
-     int *template_p;
+     int *encode_return_type;
 {
   DEMANGLE_TRACE ("class-enum-type", dm);
 
-  RETURN_IF_ERROR (demangle_name (dm, template_p));
+  RETURN_IF_ERROR (demangle_name (dm, encode_return_type));
   return STATUS_OK;
 }
 
 /* Demangles and emits an <array-type>.  
 
-    <array-type> ::= A [<dimension number>] _ <element type>  */
+    <array-type> ::= A [<dimension number>] _ <element type>  
+                 ::= A <dimension expression> _ <element type>  */
 
 static status_t
 demangle_array_type (dm)
      demangling_t dm;
 {
-  status_t status;
-  dyn_string_t array_size = dyn_string_new (10);
-
-  if (array_size == NULL)
-    return STATUS_ALLOCATION_FAILED;
+  status_t status = STATUS_OK;
+  dyn_string_t array_size = NULL;
+  char peek;
 
-  status = demangle_char (dm, 'A');
+  RETURN_IF_ERROR (demangle_char (dm, 'A'));
 
   /* Demangle the array size into array_size.  */
-  if (STATUS_NO_ERROR (status))
-    status = demangle_number_literally (dm, array_size, 10, 0);
+  peek = peek_char (dm);
+  if (peek == '_')
+    /* Array bound is omitted.  This is a C99-style VLA.  */
+    ;
+  else if (IS_DIGIT (peek_char (dm))) 
+    {
+      /* It looks like a constant array bound.  */
+      array_size = dyn_string_new (10);
+      if (array_size == NULL)
+       return STATUS_ALLOCATION_FAILED;
+      status = demangle_number_literally (dm, array_size, 10, 0);
+    }
+  else
+    {
+      /* Anything is must be an expression for a nont-constant array
+        bound.  This happens if the array type occurs in a template
+        and the array bound references a template parameter.  */
+      RETURN_IF_ERROR (result_push (dm));
+      RETURN_IF_ERROR (demangle_expression (dm));
+      array_size = (dyn_string_t) result_pop (dm);
+    }
+  /* array_size may have been allocated by now, so we can't use
+     RETURN_IF_ERROR until it's been deallocated.  */
 
   /* Demangle the base type of the array.  */
   if (STATUS_NO_ERROR (status))
@@ -2337,27 +2667,26 @@ demangle_array_type (dm)
   /* Emit the array dimension syntax.  */
   if (STATUS_NO_ERROR (status))
     status = result_append_char (dm, '[');
-  if (STATUS_NO_ERROR (status))
+  if (STATUS_NO_ERROR (status) && array_size != NULL)
     status = result_append_string (dm, array_size);
   if (STATUS_NO_ERROR (status))
     status = result_append_char (dm, ']');
-  dyn_string_delete (array_size);
+  if (array_size != NULL)
+    dyn_string_delete (array_size);
   
   RETURN_IF_ERROR (status);
 
   return STATUS_OK;
 }
 
-/* Demangles and emits a <template-param>.  The zero-indexed position
-   in the parameter list is placed in *TEMPLATE_PARM_NUMBER.  
+/* Demangles and emits a <template-param>.  
 
     <template-param> ::= T_       # first template parameter
                      ::= T <parameter-2 number> _  */
 
 static status_t
-demangle_template_param (dm, template_parm_number)
+demangle_template_param (dm)
      demangling_t dm;
-     int *template_parm_number;
 {
   int parm_number;
   template_arg_list_t current_arg_list = current_template_arg_list (dm);
@@ -2387,10 +2716,6 @@ demangle_template_param (dm, template_parm_number)
     return "Template parameter number out of bounds.";
   RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
 
-  if (peek_char (dm) == 'I')
-    RETURN_IF_ERROR (demangle_template_args (dm));
-
-  *template_parm_number = parm_number;
   return STATUS_OK;
 }
 
@@ -2419,7 +2744,7 @@ demangle_template_args (dm)
     return STATUS_ALLOCATION_FAILED;
 
   RETURN_IF_ERROR (demangle_char (dm, 'I'));
-  RETURN_IF_ERROR (result_append_char (dm, '<'));
+  RETURN_IF_ERROR (result_open_template_list (dm));
   do
     {
       string_list_t arg;
@@ -2595,6 +2920,7 @@ demangle_template_arg (dm)
       /* Expression.  */
       advance_char (dm);
       RETURN_IF_ERROR (demangle_expression (dm));
+      RETURN_IF_ERROR (demangle_char (dm, 'E'));
       break;
 
     default:
@@ -2699,12 +3025,11 @@ demangle_expr_primary (dm)
      demangling_t dm;
 {
   char peek = peek_char (dm);
-  int unused;
 
   DEMANGLE_TRACE ("expr-primary", dm);
 
   if (peek == 'T')
-    RETURN_IF_ERROR (demangle_template_param (dm, &unused));
+    RETURN_IF_ERROR (demangle_template_param (dm));
   else if (peek == 'L')
     {
       /* Consume the `L'.  */
@@ -2725,10 +3050,7 @@ demangle_expr_primary (dm)
 }
 
 /* Demangles and emits a <substitution>.  Sets *TEMPLATE_P to non-zero
-   if the substitution is the name of a template, zero otherwise.  If
-   the substitution token is St, which corresponds to the `::std::'
-   namespace and can appear in a non-nested name, sets
-   *SPECIAL_STD_SUBSTITUTION to non-zero; zero otherwise.  
+   if the substitution is the name of a template, zero otherwise. 
 
      <substitution> ::= S <seq-id> _
                     ::= S_
@@ -2744,14 +3066,13 @@ demangle_expr_primary (dm)
                     ::= So   # ::std::basic_ostream<char,  
                                                     std::char_traits<char> >
                     ::= Sd   # ::std::basic_iostream<char, 
-                                                     std::char_traits<char> >
+                                                    std::char_traits<char> >
 */
 
 static status_t
-demangle_substitution (dm, template_p, special_std_substitution)
+demangle_substitution (dm, template_p)
      demangling_t dm;
      int *template_p;
-     int *special_std_substitution;
 {
   int seq_id;
   int peek;
@@ -2760,7 +3081,6 @@ demangle_substitution (dm, template_p, special_std_substitution)
   DEMANGLE_TRACE ("substitution", dm);
 
   RETURN_IF_ERROR (demangle_char (dm, 'S'));
-  *special_std_substitution = 0;
 
   /* Scan the substitution sequence index.  A missing number denotes
      the first index.  */
@@ -2781,7 +3101,6 @@ demangle_substitution (dm, template_p, special_std_substitution)
        {
        case 't':
          RETURN_IF_ERROR (result_append (dm, "std"));
-         *special_std_substitution = 1;
          break;
 
        case 'a':
@@ -2897,7 +3216,7 @@ demangle_local_name (dm)
   RETURN_IF_ERROR (demangle_char (dm, 'Z'));
   RETURN_IF_ERROR (demangle_encoding (dm));
   RETURN_IF_ERROR (demangle_char (dm, 'E'));
-  RETURN_IF_ERROR (result_append (dm, "'s "));
+  RETURN_IF_ERROR (result_append (dm, "::"));
 
   if (peek_char (dm) == 's')
     {
@@ -2910,7 +3229,6 @@ demangle_local_name (dm)
   else
     {
       int unused;
-      RETURN_IF_ERROR (result_append (dm, "local "));
       /* Local name for some other entity.  Demangle its name.  */
       RETURN_IF_ERROR (demangle_name (dm, &unused));
       RETURN_IF_ERROR (demangle_discriminator (dm, 1));
@@ -2933,7 +3251,7 @@ demangle_discriminator (dm, suppress_first)
      int suppress_first;
 {
   /* Output for <discriminator>s to the demangled name is completely
-     supressed if not in verbose mode.  */
+     suppressed if not in verbose mode.  */
 
   if (peek_char (dm) == '_')
     {
@@ -3025,6 +3343,7 @@ cp_demangle (name, result)
    dyn_string_t.  On success, returns STATUS_OK.  On failiure, returns
    an error message, and the contents of RESULT are unchanged.  */
 
+#ifdef IN_LIBGCC2
 static status_t
 cp_demangle_type (type_name, result)
      const char* type_name;
@@ -3062,9 +3381,6 @@ cp_demangle_type (type_name, result)
   return status;
 }
 
-
-#ifdef IN_LIBGCC2
-
 extern char *__cxa_demangle PARAMS ((const char *, char *, size_t *, int *));
 
 /* ABI-mandated entry point in the C++ runtime library for performing
@@ -3221,7 +3537,8 @@ static void print_usage
 
 /* Non-zero if CHAR is a character than can occur in a mangled name.  */
 #define is_mangled_char(CHAR)                                           \
-  (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) || (CHAR) == '_')
+  (IS_ALPHA (CHAR) || IS_DIGIT (CHAR)                                   \
+   || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$')
 
 /* The name of this program, as invoked.  */
 const char* program_name;
@@ -3234,7 +3551,7 @@ print_usage (fp, exit_value)
      int exit_value;
 {
   fprintf (fp, "Usage: %s [options] [names ...]\n", program_name);
-  fprintf (fp, "Options:\n", program_name);
+  fprintf (fp, "Options:\n");
   fprintf (fp, "  -h,--help       Display this message.\n");
   fprintf (fp, "  -s,--strict     Demangle standard names only.\n");
   fprintf (fp, "  -v,--verbose    Produce verbose demanglings.\n");
index 8a672c6..3fe70b4 100644 (file)
@@ -1,5 +1,6 @@
 /* Demangler for GNU C++
-   Copyright 1989, 91, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000 Free Software Foundation, Inc.
    Written by James Clark (jjc@jclark.uucp)
    Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
    Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
@@ -705,7 +706,7 @@ cplus_demangle_opname (opname, result, options)
        {
          /* Operator.  */
          size_t i;
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              if (strlen (optable[i].in) == 2
                  && memcmp (optable[i].in, opname + 2, 2) == 0)
@@ -723,7 +724,7 @@ cplus_demangle_opname (opname, result, options)
            {
              /* Assignment.  */
              size_t i;
-             for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+             for (i = 0; i < ARRAY_SIZE (optable); i++)
                {
                  if (strlen (optable[i].in) == 3
                      && memcmp (optable[i].in, opname + 2, 3) == 0)
@@ -747,7 +748,7 @@ cplus_demangle_opname (opname, result, options)
          && memcmp (opname + 3, "assign_", 7) == 0)
        {
          size_t i;
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              len1 = len - 10;
              if ((int) strlen (optable[i].in) == len1
@@ -764,7 +765,7 @@ cplus_demangle_opname (opname, result, options)
       else
        {
          size_t i;
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              len1 = len - 3;
              if ((int) strlen (optable[i].in) == len1
@@ -811,7 +812,7 @@ cplus_mangle_opname (opname, options)
   int len;
 
   len = strlen (opname);
-  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+  for (i = 0; i < ARRAY_SIZE (optable); i++)
     {
       if ((int) strlen (optable[i].out) == len
          && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
@@ -1573,9 +1574,7 @@ demangle_expression (work, mangled, s, tk)
 
          len = strlen (*mangled);
 
-         for (i = 0;
-              i < sizeof (optable) / sizeof (optable [0]);
-              ++i)
+         for (i = 0; i < ARRAY_SIZE (optable); ++i)
            {
              size_t l = strlen (optable[i].in);
 
@@ -4449,7 +4448,7 @@ demangle_function_name (work, mangled, declp, scan)
       if (declp->p - declp->b >= 10 /* op$assign_ */
          && memcmp (declp->b + 3, "assign_", 7) == 0)
        {
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              int len = declp->p - declp->b - 10;
              if ((int) strlen (optable[i].in) == len
@@ -4465,7 +4464,7 @@ demangle_function_name (work, mangled, declp, scan)
        }
       else
        {
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              int len = declp->p - declp->b - 3;
              if ((int) strlen (optable[i].in) == len
@@ -4513,7 +4512,7 @@ demangle_function_name (work, mangled, declp, scan)
       if (declp->b[4] == '\0')
        {
          /* Operator.  */
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              if (strlen (optable[i].in) == 2
                  && memcmp (optable[i].in, declp->b + 2, 2) == 0)
@@ -4530,7 +4529,7 @@ demangle_function_name (work, mangled, declp, scan)
          if (declp->b[2] == 'a' && declp->b[5] == '\0')
            {
              /* Assignment.  */
-             for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+             for (i = 0; i < ARRAY_SIZE (optable); i++)
                {
                  if (strlen (optable[i].in) == 3
                      && memcmp (optable[i].in, declp->b + 2, 3) == 0)
@@ -4873,7 +4872,7 @@ hp_symbol_characters ()
 static const char *
 gnu_new_abi_symbol_characters ()
 {
-  return "_";
+  return "_$.";
 }
 
 
index 69897f8..34f88ad 100644 (file)
@@ -305,6 +305,30 @@ dyn_string_insert_cstr (dest, pos, src)
   return 1;
 }
 
+/* Inserts character C into DEST starting at position POS.  DEST is
+   expanded as necessary.  Returns 1 on success.  On failure,
+   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
+
+int
+dyn_string_insert_char (dest, pos, c)
+     dyn_string_t dest;
+     int pos;
+     int c;
+{
+  int i;
+
+  if (dyn_string_resize (dest, dest->length + 1) == NULL)
+    return 0;
+  /* Make room for the insertion.  Be sure to copy the NUL.  */
+  for (i = dest->length; i >= pos; --i)
+    dest->s[i + 1] = dest->s[i];
+  /* Add the new character.  */
+  dest->s[pos] = c;
+  /* Compute the new length.  */
+  ++dest->length;
+  return 1;
+}
+     
 /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
    returns 0.  */
index 9c62b57..34d2deb 100644 (file)
@@ -46,19 +46,6 @@ extern int errno;
 #include <sys/wait.h>
 #endif
 
-#ifdef vfork /* Autoconf may define this to fork for us. */
-# define VFORK_STRING "fork"
-#else
-# define VFORK_STRING "vfork"
-#endif
-#ifdef HAVE_VFORK_H
-#include <vfork.h>
-#endif
-#ifdef VMS
-#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
-               lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
-#endif /* VMS */
-
 #include "libiberty.h"
 
 /* stdin file number.  */
@@ -714,9 +701,10 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
 
   /* Fork a subprocess; wait and retry if it fails.  */
   sleep_interval = 1;
+  pid = -1;
   for (retries = 0; retries < 4; retries++)
     {
-      pid = vfork ();
+      pid = fork ();
       if (pid >= 0)
        break;
       sleep (sleep_interval);
@@ -726,11 +714,9 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
   switch (pid)
     {
     case -1:
-      {
-       *errmsg_fmt = VFORK_STRING;
-       *errmsg_arg = NULL;
-       return -1;
-      }
+      *errmsg_fmt = "fork";
+      *errmsg_arg = NULL;
+      return -1;
 
     case 0: /* child */
       /* Move the input and output pipes into place, if necessary.  */
@@ -754,7 +740,6 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
       /* Exec the program.  */
       (*func) (program, argv);
 
-      /* Note: Calling fprintf and exit here doesn't seem right for vfork.  */
       fprintf (stderr, "%s: ", this_pname);
       fprintf (stderr, install_error_msg, program);
       fprintf (stderr, ": %s\n", xstrerror (errno));
index a90c83a..f025716 100644 (file)
@@ -63,7 +63,7 @@ setenv (name, value, replace)
      const char *value;
      int replace;
 {
-  register char **ep;
+  register char **ep = 0;
   register size_t size;
   const size_t namelen = strlen (name);
   const size_t vallen = strlen (value) + 1;
index 2a09e6a..db6408d 100644 (file)
@@ -12,6 +12,8 @@
 #include <sys/types.h>
 #include <signal.h>
 
+extern void abort PARAMS ((void)) ATTRIBUTE_NORETURN;
+
 #ifdef SIG_SETMASK
 int
 DEFUN(sigsetmask,(set),
index 609cd68..52b57c0 100644 (file)
@@ -1,5 +1,5 @@
 /* A splay-tree datatype.  
-   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
    Contributed by Mark Mitchell (mark@markmitchell.com).
 
 This file is part of GNU CC.
@@ -305,8 +305,8 @@ splay_tree_insert (sp, key, value)
          node->right->left = 0;
        }
 
-    sp->root = node;
-  }
+      sp->root = node;
+    }
 
   return sp->root;
 }
@@ -368,6 +368,72 @@ splay_tree_lookup (sp, key)
     return 0;
 }
 
+/* Return the immediate predecessor KEY, or NULL if there is no
+   predecessor.  KEY need not be present in the tree.  */
+
+splay_tree_node
+splay_tree_predecessor (sp, key)
+     splay_tree sp;
+     splay_tree_key key;
+{
+  int comparison;
+  splay_tree_node node;
+
+  /* If the tree is empty, there is certainly no predecessor.  */
+  if (!sp->root)
+    return NULL;
+
+  /* Splay the tree around KEY.  That will leave either the KEY
+     itself, its predecessor, or its successor at the root.  */
+  splay_tree_splay (sp, key);
+  comparison = (*sp->comp)(sp->root->key, key);
+
+  /* If the predecessor is at the root, just return it.  */
+  if (comparison < 0)
+    return sp->root;
+
+  /* Otherwise, find the leftmost element of the right subtree.  */
+  node = sp->root->left;
+  if (node)
+    while (node->right)
+      node = node->right;
+
+  return node;
+}
+
+/* Return the immediate successor KEY, or NULL if there is no
+   predecessor.  KEY need not be present in the tree.  */
+
+splay_tree_node
+splay_tree_successor (sp, key)
+     splay_tree sp;
+     splay_tree_key key;
+{
+  int comparison;
+  splay_tree_node node;
+
+  /* If the tree is empty, there is certainly no predecessor.  */
+  if (!sp->root)
+    return NULL;
+
+  /* Splay the tree around KEY.  That will leave either the KEY
+     itself, its predecessor, or its successor at the root.  */
+  splay_tree_splay (sp, key);
+  comparison = (*sp->comp)(sp->root->key, key);
+
+  /* If the successor is at the root, just return it.  */
+  if (comparison > 0)
+    return sp->root;
+
+  /* Otherwise, find the rightmost element of the left subtree.  */
+  node = sp->root->right;
+  if (node)
+    while (node->left)
+      node = node->left;
+
+  return node;
+}
+
 /* Call FN, passing it the DATA, for every node in SP, following an
    in-order traversal.  If FN every returns a non-zero value, the
    iteration ceases immediately, and the value is returned.
index b959f5f..c34585d 100644 (file)
@@ -18,21 +18,31 @@ License along with libiberty; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-#ifdef __STDC__
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <ansidecl.h>
+#ifdef ANSI_PROTOTYPES
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
 #include <stdio.h>
 #include <string.h>
-#include <ansidecl.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern unsigned long strtoul ();
+extern PTR malloc ();
+#endif
+#include "libiberty.h"
 
 #ifdef TEST
 int global_total_width;
 #endif
 
-unsigned long strtoul ();
-char *malloc ();
+
+static int int_vasprintf PARAMS ((char **, const char *, va_list *));
 
 static int
 int_vasprintf (result, format, args)
@@ -60,7 +70,7 @@ int_vasprintf (result, format, args)
              total_width += abs (va_arg (ap, int));
            }
          else
-           total_width += strtoul (p, &p, 10);
+           total_width += strtoul (p, (char **) &p, 10);
          if (*p == '.')
            {
              ++p;
@@ -70,7 +80,7 @@ int_vasprintf (result, format, args)
                  total_width += abs (va_arg (ap, int));
                }
              else
-             total_width += strtoul (p, &p, 10);
+             total_width += strtoul (p, (char **) &p, 10);
            }
          while (strchr ("hlL", *p))
            ++p;
@@ -132,33 +142,33 @@ vasprintf (result, format, args)
 }
 
 #ifdef TEST
-void
-checkit
-#ifdef __STDC__
-     (const char* format, ...)
-#else
-     (va_alist)
-     va_dcl
-#endif
+static void checkit PARAMS ((const char *, ...));
+
+static void
+checkit VPARAMS ((const char* format, ...))
 {
   va_list args;
   char *result;
+#ifndef ANSI_PROTOTYPES
+  const char *format;
+#endif
 
-#ifdef __STDC__
-  va_start (args, format);
-#else
-  char *format;
-  va_start (args);
-  format = va_arg (args, char *);
+  VA_START (args, format);
+
+#ifndef ANSI_PROTOTYPES
+  format = va_arg (args, const char *);
 #endif
+
   vasprintf (&result, format, args);
-  if (strlen (result) < global_total_width)
+  if (strlen (result) < (size_t) global_total_width)
     printf ("PASS: ");
   else
     printf ("FAIL: ");
   printf ("%d %s\n", global_total_width, result);
 }
 
+extern int main PARAMS ((void));
+
 int
 main ()
 {
@@ -169,5 +179,7 @@ main ()
   checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
 777777777777777777333333333333366666666666622222222222777777777777733333");
   checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
+
+  return 0;
 }
 #endif /* TEST */
index 86c4591..5e87721 100644 (file)
@@ -1,6 +1,10 @@
 /* Emulate vfork using just plain fork, for systems without a real vfork.
    This function is in the public domain. */
 
+#include "ansidecl.h"
+
+extern int fork PARAMS ((void));
+
 int
 vfork ()
 {
index 7aa52ac..e8b1ed1 100644 (file)
@@ -17,13 +17,15 @@ License along with libiberty; see the file COPYING.LIB.  If not, write
 to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-#include "ansidecl.h"
-#include "libiberty.h"
-
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 #include <stdio.h>
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
+#include "libiberty.h"
+
 
 /* This variable is set by xatexit if it is called.  This way, xmalloc
    doesn't drag xatexit into the link.  */