C++ PATCH: new-ABI demangler fixes

Alex Samuel samuel@codesourcery.com
Sun Oct 22 16:58:00 GMT 2000


This patch fixes some problems with the incorrect generation of
demangled names of

  - array pointer and reference types
  - const member functions
  - CV-qualified pointers and pointers-to-member


in libiberty:

	* cp-demangle.c (string_list_def): Add caret_position and comments.
	(result_caret_pos): New macro.
	(result_append_string): Rename to...
	(result_add_string): ... this, and insert at caret position.
	Rename throughout. 
	(result_append): Rename to...
	(result_add): ... this, and insert at caret position.  Rename
	throughout. 
	(result_append_char): Rename to...
	(result_add_char): ... this, and insert at caret position.  Rename
	throughout. 
	(result_append_space): Remove.
	(string_list_new): Initialize caret position.
	(result_add_separated_char): Use caret position.
	(result_get_caret): New funtion.
	(result_set_caret): Likewise.
	(result_shift_caret): Likewise.
	(result_previous_char_is_space): Likewise.
	(substitution_start): Use caret position.
	(substitution_add): Likewise.
	(demangling_new): Initialize caret position.
	(demangle_encoding): Use caret position.
	(demanglin_nested_name): Put CV qualifiers after name. 
	(demangle_type_ptr): Use switch statement.  Handle pointers to
	arrays.  Don't use result_append_space.  Use caret position.
	(demangle_type): Emit CV qualifiers after underlying type.  Adjust
	call to demangle_array_type. 
	(demangle_array_type): Add parameter to handle pointers to arrays. 



Index: cp-demangle.c
===================================================================
RCS file: /cvs/gcc/egcs/libiberty/cp-demangle.c,v
retrieving revision 1.23
diff -c -p -r1.23 cp-demangle.c
*** cp-demangle.c	2000/09/08 17:50:54	1.23
--- cp-demangle.c	2000/10/22 23:52:44
*************** static int flag_verbose;
*** 79,91 ****
     specification -- don't demangle special g++ manglings.  */
  static int flag_strict;
  
! /* String_list_t is an extended form of dyn_string_t which provides a link
!    field.  A string_list_t may safely be cast to and used as a
!    dyn_string_t.  */
  
  struct string_list_def
  {
    struct dyn_string string;
    struct string_list_def *next;
  };
  
--- 79,100 ----
     specification -- don't demangle special g++ manglings.  */
  static int flag_strict;
  
! /* String_list_t is an extended form of dyn_string_t which provides a
!    link field and a caret position for additions to the string.  A
!    string_list_t may safely be cast to and used as a dyn_string_t.  */
  
  struct string_list_def
  {
+   /* The dyn_string; must be first.  */
    struct dyn_string string;
+ 
+   /* The position at which additional text is added to this string
+      (using the result_add* macros).  This value is an offset from the
+      end of the string, not the beginning (and should be
+      non-positive).  */
+   int caret_position;
+ 
+   /* The next string in the list.  */
    struct string_list_def *next;
  };
  
*************** static void demangling_delete 
*** 272,290 ****
  /* Returns the string containing the current demangled result.  */
  #define result_string(DM)       (&(DM)->result->string)
  
! /* Appends a dyn_string_t to the demangled result.  */
! #define result_append_string(DM, STRING)                                \
!   (dyn_string_append (&(DM)->result->string, (STRING))                  \
     ? STATUS_OK : STATUS_ALLOCATION_FAILED)
  
! /* Appends NUL-terminated string CSTR to the demangled result.  */
! #define result_append(DM, CSTR)                                         \
!   (dyn_string_append_cstr (&(DM)->result->string, (CSTR))               \
     ? STATUS_OK : STATUS_ALLOCATION_FAILED)
  
! /* Appends character CHAR to the demangled result.  */
! #define result_append_char(DM, CHAR)                                    \
!   (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.  */
--- 281,308 ----
  /* Returns the string containing the current demangled result.  */
  #define result_string(DM)       (&(DM)->result->string)
  
! /* Returns the position at which new text is inserted into the
!    demangled result.  */
! #define result_caret_pos(DM)                                            \
!   (result_length (DM) +                                                 \
!    ((string_list_t) result_string (DM))->caret_position)
! 
! /* Adds a dyn_string_t to the demangled result.  */
! #define result_add_string(DM, STRING)                                   \
!   (dyn_string_insert (&(DM)->result->string,                            \
! 		      result_caret_pos (DM), (STRING))                  \
     ? STATUS_OK : STATUS_ALLOCATION_FAILED)
  
! /* Adds NUL-terminated string CSTR to the demangled result.    */
! #define result_add(DM, CSTR)                                            \
!   (dyn_string_insert_cstr (&(DM)->result->string,                       \
! 			   result_caret_pos (DM), (CSTR))               \
     ? STATUS_OK : STATUS_ALLOCATION_FAILED)
  
! /* Adds character CHAR to the demangled result.  */
! #define result_add_char(DM, CHAR)                                       \
!   (dyn_string_insert_char (&(DM)->result->string,                       \
! 			   result_caret_pos (DM), (CHAR))               \
     ? STATUS_OK : STATUS_ALLOCATION_FAILED)
  
  /* Inserts a dyn_string_t to the demangled result at position POS.  */
*************** static void demangling_delete 
*** 307,318 ****
  #define result_length(DM)                                               \
    dyn_string_length (&(DM)->result->string)
  
- /* Appends a space to the demangled result if the last character is
-    not a space.  */
- #define result_append_space(DM)                                         \
-   (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
--- 325,330 ----
*************** string_list_new (length)
*** 380,385 ****
--- 392,398 ----
       int length;
  {
    string_list_t s = (string_list_t) malloc (sizeof (struct string_list_def));
+   s->caret_position = 0;
    if (s == NULL)
      return NULL;
    if (!dyn_string_init ((dyn_string_t) s, length))
*************** result_add_separated_char (dm, character
*** 409,428 ****
       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) == character)
!     {
!       if (!dyn_string_append_char (s, ' '))
! 	return STATUS_ALLOCATION_FAILED;
!     }
  
!   /* Add closing angle brackets.  */
!   if (!dyn_string_append_char (s, character))
!     return STATUS_ALLOCATION_FAILED;
  
    return STATUS_OK;
  }
--- 422,436 ----
       demangling_t dm;
       int character;
  {
!   char *result = dyn_string_buf (result_string (dm));
!   int caret_pos = result_caret_pos (dm);
  
!   /* Add a space if the last character is already the character we
!      want to add.  */
!   if (caret_pos > 0 && result[caret_pos - 1] == character)
!     RETURN_IF_ERROR (result_add_char (dm, ' '));
!   /* Add the character.  */
!   RETURN_IF_ERROR (result_add_char (dm, character));
  
    return STATUS_OK;
  }
*************** result_pop (dm)
*** 460,465 ****
--- 468,518 ----
    return top;
  }
  
+ /* Returns the current value of the caret for the result string.  The
+    value is an offet from the end of the result string.  */
+ 
+ static int
+ result_get_caret (dm)
+      demangling_t dm;
+ {
+   return ((string_list_t) result_string (dm))->caret_position;
+ }
+ 
+ /* Sets the value of the caret for the result string, counted as an
+    offet from the end of the result string.  */
+ 
+ static void
+ result_set_caret (dm, position)
+      demangling_t dm;
+      int position;
+ {
+   ((string_list_t) result_string (dm))->caret_position = position;
+ }
+ 
+ /* Shifts the position of the next addition to the result by
+    POSITION_OFFSET.  A negative value shifts the caret to the left.  */
+ 
+ static void
+ result_shift_caret (dm, position_offset)
+      demangling_t dm;
+      int position_offset;
+ {
+   ((string_list_t) result_string (dm))->caret_position += position_offset;
+ }
+ 
+ /* Returns non-zero if the character that comes right before the place
+    where text will be added to the result is a space.  In this case,
+    the caller should supress adding another space.  */
+ 
+ static int
+ result_previous_char_is_space (dm)
+      demangling_t dm;
+ {
+   char *result = dyn_string_buf (result_string (dm));
+   int pos = result_caret_pos (dm);
+   return pos > 0 && result[pos - 1] == ' ';
+ }
+ 
  /* Returns the start position of a fragment of the demangled result
     that will be a substitution candidate.  Should be called at the
     start of productions that can add substitutions.  */
*************** static int
*** 468,474 ****
  substitution_start (dm)
       demangling_t dm;
  {
!   return result_length (dm);
  }
  
  /* Adds the suffix of the current demangled result of DM starting at
--- 521,527 ----
  substitution_start (dm)
       demangling_t dm;
  {
!   return result_caret_pos (dm);
  }
  
  /* Adds the suffix of the current demangled result of DM starting at
*************** substitution_add (dm, start_position, te
*** 491,497 ****
    /* Extract the substring of the current demangling result that
       represents the subsitution candidate.  */
    if (!dyn_string_substring (substitution, 
! 			     result, start_position, result_length (dm)))
      {
        dyn_string_delete (substitution);
        return STATUS_ALLOCATION_FAILED;
--- 544,550 ----
    /* Extract the substring of the current demangling result that
       represents the subsitution candidate.  */
    if (!dyn_string_substring (substitution, 
! 			     result, start_position, result_caret_pos (dm)))
      {
        dyn_string_delete (substitution);
        return STATUS_ALLOCATION_FAILED;
*************** static status_t demangle_bare_function_t
*** 843,849 ****
  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));
  static status_t demangle_template_args
--- 896,902 ----
  static status_t demangle_class_enum_type
    PARAMS ((demangling_t, int *));
  static status_t demangle_array_type
!   PARAMS ((demangling_t, int *));
  static status_t demangle_template_param
    PARAMS ((demangling_t));
  static status_t demangle_template_args
*************** demangle_encoding (dm)
*** 933,939 ****
    
    /* Remember where the name starts.  If it turns out to be a template
       function, we'll have to insert the return type here.  */
!   start_position = result_length (dm);
  
    if (peek == 'G' || peek == 'T')
      RETURN_IF_ERROR (demangle_special_name (dm));
--- 986,992 ----
    
    /* Remember where the name starts.  If it turns out to be a template
       function, we'll have to insert the return type here.  */
!   start_position = result_caret_pos (dm);
  
    if (peek == 'G' || peek == 'T')
      RETURN_IF_ERROR (demangle_special_name (dm));
*************** demangle_encoding (dm)
*** 943,949 ****
        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')
  	{
--- 996,1002 ----
        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 parameter types, following.  */
        if (!end_of_name_p (dm) 
  	  && peek_char (dm) != 'E')
  	{
*************** demangle_name (dm, encode_return_type)
*** 1017,1023 ****
  	{
  	  (void) next_char (dm);
  	  (void) next_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "std::"));
  	  RETURN_IF_ERROR 
  	    (demangle_unqualified_name (dm, &suppress_return_type));
  	  is_std_substitution = 1;
--- 1070,1076 ----
  	{
  	  (void) next_char (dm);
  	  (void) next_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "std::"));
  	  RETURN_IF_ERROR 
  	    (demangle_unqualified_name (dm, &suppress_return_type));
  	  is_std_substitution = 1;
*************** demangle_nested_name (dm, encode_return_
*** 1082,1101 ****
    peek = peek_char (dm);
    if (peek == 'r' || peek == 'V' || peek == 'K')
      {
        status_t status;
  
!       /* Snarf up and emit CV qualifiers.  */
!       dyn_string_t cv_qualifiers = dyn_string_new (24);
        if (cv_qualifiers == NULL)
  	return STATUS_ALLOCATION_FAILED;
- 
        demangle_CV_qualifiers (dm, cv_qualifiers);
!       status = result_append_string (dm, cv_qualifiers);
        dyn_string_delete (cv_qualifiers);
        RETURN_IF_ERROR (status);
-       RETURN_IF_ERROR (result_append_space (dm));
      }
!   
    RETURN_IF_ERROR (demangle_prefix (dm, encode_return_type));
    /* No need to demangle the final <unqualified-name>; demangle_prefix
       will handle it.  */
--- 1135,1164 ----
    peek = peek_char (dm);
    if (peek == 'r' || peek == 'V' || peek == 'K')
      {
+       dyn_string_t cv_qualifiers;
        status_t status;
  
!       /* Snarf up CV qualifiers.  */
!       cv_qualifiers = dyn_string_new (24);
        if (cv_qualifiers == NULL)
  	return STATUS_ALLOCATION_FAILED;
        demangle_CV_qualifiers (dm, cv_qualifiers);
! 
!       /* Emit them, preceded by a space.  */
!       status = result_add_char (dm, ' ');
!       if (STATUS_NO_ERROR (status)) 
! 	status = result_add_string (dm, cv_qualifiers);
!       /* The CV qualifiers that occur in a <nested-name> will be
! 	 qualifiers for member functions.  These are placed at the end
! 	 of the function.  Therefore, shift the caret to the left by
! 	 the length of the qualifiers, so other text is inserted
! 	 before them and they stay at the end.  */
!       result_shift_caret (dm, -dyn_string_length (cv_qualifiers) - 1);
!       /* Clean up.  */
        dyn_string_delete (cv_qualifiers);
        RETURN_IF_ERROR (status);
      }
! 
    RETURN_IF_ERROR (demangle_prefix (dm, encode_return_type));
    /* No need to demangle the final <unqualified-name>; demangle_prefix
       will handle it.  */
*************** demangle_prefix (dm, encode_return_type)
*** 1159,1165 ****
  	{
  	  /* We have another level of scope qualification.  */
  	  if (nested)
! 	    RETURN_IF_ERROR (result_append (dm, "::"));
  	  else
  	    nested = 1;
  
--- 1222,1228 ----
  	{
  	  /* We have another level of scope qualification.  */
  	  if (nested)
! 	    RETURN_IF_ERROR (result_add (dm, "::"));
  	  else
  	    nested = 1;
  
*************** demangle_source_name (dm)
*** 1275,1281 ****
  					dm->last_source_name));
  
    /* Emit it.  */
!   RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
  
    return STATUS_OK;
  }
--- 1338,1344 ----
  					dm->last_source_name));
  
    /* Emit it.  */
!   RETURN_IF_ERROR (result_add_string (dm, dm->last_source_name));
  
    return STATUS_OK;
  }
*************** demangle_operator_name (dm, short_name, 
*** 1547,1553 ****
    /* Is this a vendor-extended operator?  */
    if (c0 == 'v' && IS_DIGIT (c1))
      {
!       RETURN_IF_ERROR (result_append (dm, "operator "));
        RETURN_IF_ERROR (demangle_source_name (dm));
        *num_args = 0;
        return STATUS_OK;
--- 1610,1616 ----
    /* Is this a vendor-extended operator?  */
    if (c0 == 'v' && IS_DIGIT (c1))
      {
!       RETURN_IF_ERROR (result_add (dm, "operator "));
        RETURN_IF_ERROR (demangle_source_name (dm));
        *num_args = 0;
        return STATUS_OK;
*************** demangle_operator_name (dm, short_name, 
*** 1556,1562 ****
    /* Is this a conversion operator?  */
    if (c0 == 'c' && c1 == 'v')
      {
!       RETURN_IF_ERROR (result_append (dm, "operator "));
        /* Demangle the converted-to type.  */
        RETURN_IF_ERROR (demangle_type (dm));
        *num_args = 0;
--- 1619,1625 ----
    /* Is this a conversion operator?  */
    if (c0 == 'c' && c1 == 'v')
      {
!       RETURN_IF_ERROR (result_add (dm, "operator "));
        /* Demangle the converted-to type.  */
        RETURN_IF_ERROR (demangle_type (dm));
        *num_args = 0;
*************** demangle_operator_name (dm, short_name, 
*** 1574,1581 ****
  	/* Found it.  */
  	{
  	  if (!short_name)
! 	    RETURN_IF_ERROR (result_append (dm, "operator"));
! 	  RETURN_IF_ERROR (result_append (dm, p->name));
  	  *num_args = p->num_args;
  
  	  return STATUS_OK;
--- 1637,1644 ----
  	/* Found it.  */
  	{
  	  if (!short_name)
! 	    RETURN_IF_ERROR (result_add (dm, "operator"));
! 	  RETURN_IF_ERROR (result_add (dm, p->name));
  	  *num_args = p->num_args;
  
  	  return STATUS_OK;
*************** demangle_nv_offset (dm)
*** 1615,1625 ****
    /* 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.  */
--- 1678,1688 ----
    /* Don't display the offset unless in verbose mode.  */
    if (flag_verbose)
      {
!       status = result_add (dm, " [nv:");
        if (STATUS_NO_ERROR (status))
! 	status = result_add_string (dm, number);
        if (STATUS_NO_ERROR (status))
! 	status = result_add_char (dm, ']');
      }
  
    /* Clean up.  */
*************** demangle_v_offset (dm)
*** 1651,1661 ****
    /* 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);
--- 1714,1724 ----
    /* Don't display the offset unless in verbose mode.  */
    if (flag_verbose)
      {
!       status = result_add (dm, " [v:");
        if (STATUS_NO_ERROR (status))
! 	status = result_add_string (dm, number);
        if (STATUS_NO_ERROR (status))
! 	result_add_char (dm, ',');
      }
    dyn_string_delete (number);
    RETURN_IF_ERROR (status);
*************** demangle_v_offset (dm)
*** 1672,1680 ****
    /* 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);
--- 1735,1743 ----
    /* Don't display the vcall offset unless in verbose mode.  */
    if (flag_verbose)
      {
!       status = result_add_string (dm, number);
        if (STATUS_NO_ERROR (status))
! 	status = result_add_char (dm, ']');
      }
    dyn_string_delete (number);
    RETURN_IF_ERROR (status);
*************** demangle_special_name (dm)
*** 1763,1769 ****
        /* A guard variable name.  Consume the G.  */
        advance_char (dm);
        RETURN_IF_ERROR (demangle_char (dm, 'V'));
!       RETURN_IF_ERROR (result_append (dm, "guard variable for "));
        RETURN_IF_ERROR (demangle_name (dm, &unused));
      }
    else if (peek == 'T')
--- 1826,1832 ----
        /* A guard variable name.  Consume the G.  */
        advance_char (dm);
        RETURN_IF_ERROR (demangle_char (dm, 'V'));
!       RETURN_IF_ERROR (result_add (dm, "guard variable for "));
        RETURN_IF_ERROR (demangle_name (dm, &unused));
      }
    else if (peek == 'T')
*************** demangle_special_name (dm)
*** 1778,1854 ****
  	case 'V':
  	  /* Virtual table.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "vtable for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'T':
  	  /* VTT structure.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "VTT for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'I':
  	  /* Typeinfo structure.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "typeinfo for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'F':
  	  /* Typeinfo function.  Used only in old ABI with new mangling.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "typeinfo fn for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'S':
  	  /* Character string containing type name, used in typeinfo. */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "typeinfo name for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'J':
  	  /* The java Class variable corresponding to a C++ class.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "java Class for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'h':
  	  /* Non-virtual thunk.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_append (dm, "non-virtual thunk"));
  	  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.  */
! 	  RETURN_IF_ERROR (result_append (dm, " to "));
  	  RETURN_IF_ERROR (demangle_encoding (dm));
  	  break;
  
  	case 'v':
  	  /* Virtual thunk.  */
  	  advance_char (dm);
! 	  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 (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;
  
--- 1841,1917 ----
  	case 'V':
  	  /* Virtual table.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "vtable for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'T':
  	  /* VTT structure.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "VTT for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'I':
  	  /* Typeinfo structure.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "typeinfo for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'F':
  	  /* Typeinfo function.  Used only in old ABI with new mangling.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "typeinfo fn for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'S':
  	  /* Character string containing type name, used in typeinfo. */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "typeinfo name for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'J':
  	  /* The java Class variable corresponding to a C++ class.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "java Class for "));
  	  RETURN_IF_ERROR (demangle_type (dm));
  	  break;
  
  	case 'h':
  	  /* Non-virtual thunk.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (dm, "non-virtual thunk"));
  	  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.  */
! 	  RETURN_IF_ERROR (result_add (dm, " to "));
  	  RETURN_IF_ERROR (demangle_encoding (dm));
  	  break;
  
  	case 'v':
  	  /* Virtual thunk.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (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_add (dm, " to "));
  	  RETURN_IF_ERROR (demangle_encoding (dm));
  	  break;
  
  	case 'c':
  	  /* Covariant return thunk.  */
  	  advance_char (dm);
! 	  RETURN_IF_ERROR (result_add (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_add (dm, " to "));
  	  RETURN_IF_ERROR (demangle_encoding (dm));
  	  break;
  
*************** demangle_special_name (dm)
*** 1859,1865 ****
  	      dyn_string_t derived_type;
  
  	      advance_char (dm);
! 	      RETURN_IF_ERROR (result_append (dm, "construction vtable for "));
  
  	      /* Demangle the derived type off to the side.  */
  	      RETURN_IF_ERROR (result_push (dm));
--- 1922,1928 ----
  	      dyn_string_t derived_type;
  
  	      advance_char (dm);
! 	      RETURN_IF_ERROR (result_add (dm, "construction vtable for "));
  
  	      /* Demangle the derived type off to the side.  */
  	      RETURN_IF_ERROR (result_push (dm));
*************** demangle_special_name (dm)
*** 1883,1899 ****
  
  	      /* Emit the derived type.  */
  	      if (STATUS_NO_ERROR (status))
! 		status = result_append (dm, "-in-");
  	      if (STATUS_NO_ERROR (status))
! 		status = result_append_string (dm, derived_type);
  	      dyn_string_delete (derived_type);
  
  	      /* Don't display the offset unless in verbose mode.  */
  	      if (flag_verbose)
  		{
! 		  status = result_append_char (dm, ' ');
  		  if (STATUS_NO_ERROR (status))
! 		    result_append_string (dm, number);
  		}
  	      dyn_string_delete (number);
  	      RETURN_IF_ERROR (status);
--- 1946,1962 ----
  
  	      /* Emit the derived type.  */
  	      if (STATUS_NO_ERROR (status))
! 		status = result_add (dm, "-in-");
  	      if (STATUS_NO_ERROR (status))
! 		status = result_add_string (dm, derived_type);
  	      dyn_string_delete (derived_type);
  
  	      /* Don't display the offset unless in verbose mode.  */
  	      if (flag_verbose)
  		{
! 		  status = result_add_char (dm, ' ');
  		  if (STATUS_NO_ERROR (status))
! 		    result_add_string (dm, number);
  		}
  	      dyn_string_delete (number);
  	      RETURN_IF_ERROR (status);
*************** demangle_ctor_dtor_name (dm)
*** 1949,1962 ****
        advance_char (dm);
        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.  */
        flavor = next_char (dm) - '1';
        if (flag_verbose)
  	{
! 	  RETURN_IF_ERROR (result_append (dm, "["));
! 	  RETURN_IF_ERROR (result_append (dm, ctor_flavors[flavor]));
! 	  RETURN_IF_ERROR (result_append_char (dm, ']'));
  	}
      }
    else if (peek == 'D')
--- 2012,2025 ----
        advance_char (dm);
        if (peek_char (dm) < '1' || peek_char (dm) > '3')
  	return "Unrecognized constructor.";
!       RETURN_IF_ERROR (result_add_string (dm, dm->last_source_name));
        /* Print the flavor of the constructor if in verbose mode.  */
        flavor = next_char (dm) - '1';
        if (flag_verbose)
  	{
! 	  RETURN_IF_ERROR (result_add (dm, "["));
! 	  RETURN_IF_ERROR (result_add (dm, ctor_flavors[flavor]));
! 	  RETURN_IF_ERROR (result_add_char (dm, ']'));
  	}
      }
    else if (peek == 'D')
*************** demangle_ctor_dtor_name (dm)
*** 1965,1979 ****
        advance_char (dm);
        if (peek_char (dm) < '0' || peek_char (dm) > '2')
  	return "Unrecognized destructor.";
!       RETURN_IF_ERROR (result_append_char (dm, '~'));
!       RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
        /* Print the flavor of the destructor if in verbose mode.  */
        flavor = next_char (dm) - '0';
        if (flag_verbose)
  	{
! 	  RETURN_IF_ERROR (result_append (dm, " ["));
! 	  RETURN_IF_ERROR (result_append (dm, dtor_flavors[flavor]));
! 	  RETURN_IF_ERROR (result_append_char (dm, ']'));
  	}
      }
    else
--- 2028,2042 ----
        advance_char (dm);
        if (peek_char (dm) < '0' || peek_char (dm) > '2')
  	return "Unrecognized destructor.";
!       RETURN_IF_ERROR (result_add_char (dm, '~'));
!       RETURN_IF_ERROR (result_add_string (dm, dm->last_source_name));
        /* Print the flavor of the destructor if in verbose mode.  */
        flavor = next_char (dm) - '0';
        if (flag_verbose)
  	{
! 	  RETURN_IF_ERROR (result_add (dm, " ["));
! 	  RETURN_IF_ERROR (result_add (dm, dtor_flavors[flavor]));
! 	  RETURN_IF_ERROR (result_add_char (dm, ']'));
  	}
      }
    else
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2014,2020 ****
       int *insert_pos;
       int substitution_start;
  {
-   char next;
    status_t status;
    int is_substitution_candidate = 1;
  
--- 2077,2082 ----
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2022,2030 ****
  
    /* Scan forward, collecting pointers and references into symbols,
       until we hit something else.  Then emit the type.  */
!   next = peek_char (dm);
!   if (next == 'P')
      {
        /* A pointer.  Snarf the `P'.  */
        advance_char (dm);
        /* Demangle the underlying type.  */
--- 2084,2092 ----
  
    /* Scan forward, collecting pointers and references into symbols,
       until we hit something else.  Then emit the type.  */
!   switch (peek_char (dm))
      {
+     case 'P':
        /* A pointer.  Snarf the `P'.  */
        advance_char (dm);
        /* Demangle the underlying type.  */
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2036,2044 ****
        /* 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.  */
--- 2098,2106 ----
        /* The next (outermost) pointer or reference character should go
  	 after this one.  */
        ++(*insert_pos);
!       break;
! 
!     case 'R':
        /* A reference.  Snarf the `R'.  */
        advance_char (dm);
        /* Demangle the underlying type.  */
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2050,2057 ****
        /* 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;
--- 2112,2120 ----
        /* The next (outermost) pointer or reference character should go
  	 after this one.  */
        ++(*insert_pos);
!       break;
! 
!     case 'M':
      {
        /* A pointer-to-member.  */
        dyn_string_t class_type;
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2071,2087 ****
  	   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);
  	  /* The pointer-to-member notation (e.g. `C::*') follows the
               member's type.  */
! 	  *insert_pos = result_length (dm);
  	}
  
        /* Build the pointer-to-member notation.  */
--- 2134,2157 ----
  	   and set *insert_pos to the spot between the first
  	   parentheses.  */
  	status = demangle_type_ptr (dm, insert_pos, substitution_start);
+       else if (peek_char (dm) == 'A')
+ 	/* A pointer-to-member array variable.  We want output that
+ 	   looks like `int (Klass::*) [10]'.  Demangle the array type
+ 	   as `int () [10]', and set *insert_pos to the spot between
+ 	   the parentheses.  */
+ 	status = demangle_array_type (dm, insert_pos);
        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)
! 	      && !result_previous_char_is_space (dm))
! 	    status = result_add_char (dm, ' ');
  	  /* The pointer-to-member notation (e.g. `C::*') follows the
               member's type.  */
! 	  *insert_pos = result_caret_pos (dm);
  	}
  
        /* Build the pointer-to-member notation.  */
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2100,2114 ****
  
        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.  */
--- 2170,2185 ----
  
        RETURN_IF_ERROR (status);
      }
!     break;
! 
!     case '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_caret_pos (dm);
        /* The parentheses indicate this is a function pointer or
  	 reference type.  */
!       RETURN_IF_ERROR (result_add (dm, "()"));
        /* Now demangle the function type.  The return type will be
  	 inserted before the `()', and the argument list will go after
  	 it.  */
*************** demangle_type_ptr (dm, insert_pos, subst
*** 2120,2139 ****
  	 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)
--- 2191,2217 ----
  	 type.  Move it one character over so it points inside the
  	 `()'.  */
        ++(*insert_pos);
!       break;
! 
!     case 'A':
!       /* An array pointer or reference.  demangle_array_type will figure
! 	 out where the asterisks and ampersands go.  */
!       RETURN_IF_ERROR (demangle_array_type (dm, insert_pos));
!       break;
! 
!     default:
        /* 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_caret_pos (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;
+       break;
      }
    
    if (is_substitution_candidate)
*************** demangle_type (dm)
*** 2201,2234 ****
  	{
  	  status_t status;
  	  dyn_string_t cv_qualifiers = dyn_string_new (24);
  
  	  if (cv_qualifiers == NULL)
  	    return STATUS_ALLOCATION_FAILED;
  
  	  demangle_CV_qualifiers (dm, cv_qualifiers);
! 
! 	  /* If the qualifiers apply to a pointer or reference, they
! 	     need to come after the whole qualified type.  */
! 	  if (peek_char (dm) == 'P' || peek_char (dm) == 'R')
! 	    {
! 	      status = demangle_type (dm);
! 	      if (STATUS_NO_ERROR (status))
! 		status = result_append_space (dm);
! 	      if (STATUS_NO_ERROR (status))
! 		status = result_append_string (dm, cv_qualifiers);
! 	    }
! 	  /* Otherwise, the qualifiers come first.  */
! 	  else
! 	    {
! 	      status = result_append_string (dm, cv_qualifiers);
! 	      if (STATUS_NO_ERROR (status))
! 		status = result_append_space (dm);
! 	      if (STATUS_NO_ERROR (status))
! 		status = demangle_type (dm);
! 	    }
! 
  	  dyn_string_delete (cv_qualifiers);
  	  RETURN_IF_ERROR (status);
  	}
  	break;
  
--- 2279,2308 ----
  	{
  	  status_t status;
  	  dyn_string_t cv_qualifiers = dyn_string_new (24);
+ 	  int old_caret_position = result_get_caret (dm);
  
  	  if (cv_qualifiers == NULL)
  	    return STATUS_ALLOCATION_FAILED;
  
+ 	  /* Decode all adjacent CV qualifiers.  */
  	  demangle_CV_qualifiers (dm, cv_qualifiers);
! 	  /* Emit them, and shift the caret left so that the
! 	     underlying type will be emitted before the qualifiers.  */
! 	  status = result_add_string (dm, cv_qualifiers);
! 	  result_shift_caret (dm, -dyn_string_length (cv_qualifiers));
! 	  /* Clean up.  */
  	  dyn_string_delete (cv_qualifiers);
  	  RETURN_IF_ERROR (status);
+ 	  /* Also prepend a blank, if needed.  */
+ 	  RETURN_IF_ERROR (result_add_char (dm, ' '));
+ 	  result_shift_caret (dm, -1);
+ 
+ 	  /* Demangle the underlying type.  It will be emitted before
+ 	     the CV qualifiers, since we moved the caret.  */
+ 	  RETURN_IF_ERROR (demangle_type (dm));
+ 
+ 	  /* Put the caret back where it was previously.  */
+ 	  result_set_caret (dm, old_caret_position);
  	}
  	break;
  
*************** demangle_type (dm)
*** 2236,2242 ****
  	return "Non-pointer or -reference function type.";
  
        case 'A':
! 	RETURN_IF_ERROR (demangle_array_type (dm));
  	break;
  
        case 'T':
--- 2310,2316 ----
  	return "Non-pointer or -reference function type.";
  
        case 'A':
! 	RETURN_IF_ERROR (demangle_array_type (dm, NULL));
  	break;
  
        case 'T':
*************** demangle_type (dm)
*** 2325,2338 ****
  
        case 'C':
  	/* A C99 complex type.  */
! 	RETURN_IF_ERROR (result_append (dm, "complex "));
  	advance_char (dm);
  	RETURN_IF_ERROR (demangle_type (dm));
  	break;
  
        case 'G':
  	/* A C99 imaginary type.  */
! 	RETURN_IF_ERROR (result_append (dm, "imaginary "));
  	advance_char (dm);
  	RETURN_IF_ERROR (demangle_type (dm));
  	break;
--- 2399,2412 ----
  
        case 'C':
  	/* A C99 complex type.  */
! 	RETURN_IF_ERROR (result_add (dm, "complex "));
  	advance_char (dm);
  	RETURN_IF_ERROR (demangle_type (dm));
  	break;
  
        case 'G':
  	/* A C99 imaginary type.  */
! 	RETURN_IF_ERROR (result_add (dm, "imaginary "));
  	advance_char (dm);
  	RETURN_IF_ERROR (demangle_type (dm));
  	break;
*************** demangle_type (dm)
*** 2341,2347 ****
  	/* Vendor-extended type qualifier.  */
  	advance_char (dm);
  	RETURN_IF_ERROR (demangle_source_name (dm));
! 	RETURN_IF_ERROR (result_append_char (dm, ' '));
  	RETURN_IF_ERROR (demangle_type (dm));
  	break;
  
--- 2415,2421 ----
  	/* Vendor-extended type qualifier.  */
  	advance_char (dm);
  	RETURN_IF_ERROR (demangle_source_name (dm));
! 	RETURN_IF_ERROR (result_add_char (dm, ' '));
  	RETURN_IF_ERROR (demangle_type (dm));
  	break;
  
*************** demangle_builtin_type (dm)
*** 2441,2447 ****
        if (type_name == NULL)
  	return "Unrecognized <builtin-type> code.";
  
!       RETURN_IF_ERROR (result_append (dm, type_name));
        advance_char (dm);
        return STATUS_OK;
      }
--- 2515,2521 ----
        if (type_name == NULL)
  	return "Unrecognized <builtin-type> code.";
  
!       RETURN_IF_ERROR (result_add (dm, type_name));
        advance_char (dm);
        return STATUS_OK;
      }
*************** demangle_function_type (dm, function_nam
*** 2512,2518 ****
      {
        /* Indicate this function has C linkage if in verbose mode.  */
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_append (dm, " [extern \"C\"] "));
        advance_char (dm);
      }
    RETURN_IF_ERROR (demangle_bare_function_type (dm, function_name_pos));
--- 2586,2592 ----
      {
        /* Indicate this function has C linkage if in verbose mode.  */
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_add (dm, " [extern \"C\"] "));
        advance_char (dm);
      }
    RETURN_IF_ERROR (demangle_bare_function_type (dm, function_name_pos));
*************** demangle_bare_function_type (dm, return_
*** 2539,2545 ****
  
    DEMANGLE_TRACE ("bare-function-type", dm);
  
!   RETURN_IF_ERROR (result_append_char (dm, '('));
    while (!end_of_name_p (dm) && peek_char (dm) != 'E')
      {
        if (sequence == -1)
--- 2613,2619 ----
  
    DEMANGLE_TRACE ("bare-function-type", dm);
  
!   RETURN_IF_ERROR (result_add_char (dm, '('));
    while (!end_of_name_p (dm) && peek_char (dm) != 'E')
      {
        if (sequence == -1)
*************** demangle_bare_function_type (dm, return_
*** 2581,2587 ****
  	    {
  	      /* Separate parameter types by commas.  */
  	      if (sequence > 0)
! 		RETURN_IF_ERROR (result_append (dm, ", "));
  	      /* Demangle the type.  */
  	      RETURN_IF_ERROR (demangle_type (dm));
  	    }
--- 2655,2661 ----
  	    {
  	      /* Separate parameter types by commas.  */
  	      if (sequence > 0)
! 		RETURN_IF_ERROR (result_add (dm, ", "));
  	      /* Demangle the type.  */
  	      RETURN_IF_ERROR (demangle_type (dm));
  	    }
*************** demangle_bare_function_type (dm, return_
*** 2589,2595 ****
  
        ++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
--- 2663,2669 ----
  
        ++sequence;
      }
!   RETURN_IF_ERROR (result_add_char (dm, ')'));
  
    /* We should have demangled at least one parameter type (which would
       be void, for a function that takes no parameters), plus the
*************** demangle_class_enum_type (dm, encode_ret
*** 2620,2636 ****
  
  /* Demangles and emits an <array-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 = STATUS_OK;
    dyn_string_t array_size = NULL;
    char peek;
  
    RETURN_IF_ERROR (demangle_char (dm, 'A'));
  
    /* Demangle the array size into array_size.  */
--- 2694,2725 ----
  
  /* Demangles and emits an <array-type>.  
  
+    If PTR_INSERT_POS is not NULL, the array type is formatted as a
+    pointer or reference to an array, except that asterisk and
+    ampersand punctuation is omitted (since it's not know at this
+    point).  *PTR_INSERT_POS is set to the position in the demangled
+    name at which this punctuation should be inserted.  For example,
+    `A10_i' is demangled to `int () [10]' and *PTR_INSERT_POS points
+    between the parentheses.
+ 
+    If PTR_INSERT_POS is NULL, the array type is assumed not to be
+    pointer- or reference-qualified.  Then, for example, `A10_i' is
+    demangled simply as `int[10]'.  
+ 
      <array-type> ::= A [<dimension number>] _ <element type>  
                   ::= A <dimension expression> _ <element type>  */
  
  static status_t
! demangle_array_type (dm, ptr_insert_pos)
       demangling_t dm;
+      int *ptr_insert_pos;
  {
    status_t status = STATUS_OK;
    dyn_string_t array_size = NULL;
    char peek;
  
+   DEMANGLE_TRACE ("array-type", dm);
+ 
    RETURN_IF_ERROR (demangle_char (dm, 'A'));
  
    /* Demangle the array size into array_size.  */
*************** demangle_array_type (dm)
*** 2664,2676 ****
    if (STATUS_NO_ERROR (status))
      status = demangle_type (dm);
  
    /* Emit the array dimension syntax.  */
    if (STATUS_NO_ERROR (status))
!     status = result_append_char (dm, '[');
    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, ']');
    if (array_size != NULL)
      dyn_string_delete (array_size);
    
--- 2753,2776 ----
    if (STATUS_NO_ERROR (status))
      status = demangle_type (dm);
  
+   if (ptr_insert_pos != NULL)
+     {
+       /* This array is actually part of an pointer- or
+ 	 reference-to-array type.  Format appropriately, except we
+ 	 don't know which and how much punctuation to use.  */
+       if (STATUS_NO_ERROR (status))
+ 	status = result_add (dm, " () ");
+       /* Let the caller know where to insert the punctuation.  */
+       *ptr_insert_pos = result_caret_pos (dm) - 2;
+     }
+ 
    /* Emit the array dimension syntax.  */
    if (STATUS_NO_ERROR (status))
!     status = result_add_char (dm, '[');
    if (STATUS_NO_ERROR (status) && array_size != NULL)
!     status = result_add_string (dm, array_size);
    if (STATUS_NO_ERROR (status))
!     status = result_add_char (dm, ']');
    if (array_size != NULL)
      dyn_string_delete (array_size);
    
*************** demangle_template_param (dm)
*** 2714,2720 ****
      /* parm_number exceeded the number of arguments in the current
         template argument list.  */
      return "Template parameter number out of bounds.";
!   RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
  
    return STATUS_OK;
  }
--- 2814,2820 ----
      /* parm_number exceeded the number of arguments in the current
         template argument list.  */
      return "Template parameter number out of bounds.";
!   RETURN_IF_ERROR (result_add_string (dm, (dyn_string_t) arg));
  
    return STATUS_OK;
  }
*************** demangle_template_args (dm)
*** 2752,2758 ****
        if (first)
  	first = 0;
        else
! 	RETURN_IF_ERROR (result_append (dm, ", "));
  
        /* Capture the template arg.  */
        RETURN_IF_ERROR (result_push (dm));
--- 2852,2858 ----
        if (first)
  	first = 0;
        else
! 	RETURN_IF_ERROR (result_add (dm, ", "));
  
        /* Capture the template arg.  */
        RETURN_IF_ERROR (result_push (dm));
*************** demangle_template_args (dm)
*** 2760,2766 ****
        arg = result_pop (dm);
  
        /* Emit it in the demangled name.  */
!       RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
  
        /* Save it for use in expanding <template-param>s.  */
        template_arg_list_add_arg (arg_list, arg);
--- 2860,2866 ----
        arg = result_pop (dm);
  
        /* Emit it in the demangled name.  */
!       RETURN_IF_ERROR (result_add_string (dm, (dyn_string_t) arg));
  
        /* Save it for use in expanding <template-param>s.  */
        template_arg_list_add_arg (arg_list, arg);
*************** demangle_literal (dm)
*** 2836,2844 ****
  	     corresponding to false or true, respectively.  */
  	  value = peek_char (dm);
  	  if (value == '0')
! 	    RETURN_IF_ERROR (result_append (dm, "false"));
  	  else if (value == '1')
! 	    RETURN_IF_ERROR (result_append (dm, "true"));
  	  else
  	    return "Unrecognized bool constant.";
  	  /* Consume the 0 or 1.  */
--- 2936,2944 ----
  	     corresponding to false or true, respectively.  */
  	  value = peek_char (dm);
  	  if (value == '0')
! 	    RETURN_IF_ERROR (result_add (dm, "false"));
  	  else if (value == '1')
! 	    RETURN_IF_ERROR (result_add (dm, "true"));
  	  else
  	    return "Unrecognized bool constant.";
  	  /* Consume the 0 or 1.  */
*************** demangle_literal (dm)
*** 2856,2865 ****
  	  value_string = dyn_string_new (0);
  	  status = demangle_number_literally (dm, value_string, 10, 1);
  	  if (STATUS_NO_ERROR (status))
! 	    status = result_append_string (dm, value_string);
  	  /* For long integers, append an l.  */
  	  if (code == 'l' && STATUS_NO_ERROR (status))
! 	    status = result_append_char (dm, code);
  	  dyn_string_delete (value_string);
  
  	  RETURN_IF_ERROR (status);
--- 2956,2965 ----
  	  value_string = dyn_string_new (0);
  	  status = demangle_number_literally (dm, value_string, 10, 1);
  	  if (STATUS_NO_ERROR (status))
! 	    status = result_add_string (dm, value_string);
  	  /* For long integers, append an l.  */
  	  if (code == 'l' && STATUS_NO_ERROR (status))
! 	    status = result_add_char (dm, code);
  	  dyn_string_delete (value_string);
  
  	  RETURN_IF_ERROR (status);
*************** demangle_literal (dm)
*** 2869,2877 ****
  	 literal's type explicitly using cast syntax.  */
      }
  
!   RETURN_IF_ERROR (result_append_char (dm, '('));
    RETURN_IF_ERROR (demangle_type (dm));
!   RETURN_IF_ERROR (result_append_char (dm, ')'));
  
    value_string = dyn_string_new (0);
    if (value_string == NULL)
--- 2969,2977 ----
  	 literal's type explicitly using cast syntax.  */
      }
  
!   RETURN_IF_ERROR (result_add_char (dm, '('));
    RETURN_IF_ERROR (demangle_type (dm));
!   RETURN_IF_ERROR (result_add_char (dm, ')'));
  
    value_string = dyn_string_new (0);
    if (value_string == NULL)
*************** demangle_literal (dm)
*** 2879,2885 ****
  
    status = demangle_number_literally (dm, value_string, 10, 1);
    if (STATUS_NO_ERROR (status))
!     status = result_append_string (dm, value_string);
    dyn_string_delete (value_string);
    RETURN_IF_ERROR (status);
  
--- 2979,2985 ----
  
    status = demangle_number_literally (dm, value_string, 10, 1);
    if (STATUS_NO_ERROR (status))
!     status = result_add_string (dm, value_string);
    dyn_string_delete (value_string);
    RETURN_IF_ERROR (status);
  
*************** demangle_expression (dm)
*** 2967,2996 ****
        /* If it's binary, do an operand first.  */
        if (num_args > 1)
  	{
! 	  status = result_append_char (dm, '(');
  	  if (STATUS_NO_ERROR (status))
  	    status = demangle_expression (dm);
  	  if (STATUS_NO_ERROR (status))
! 	    status = result_append_char (dm, ')');
  	}
  
        /* Emit the operator.  */  
        if (STATUS_NO_ERROR (status))
! 	status = result_append_string (dm, operator_name);
        dyn_string_delete (operator_name);
        RETURN_IF_ERROR (status);
        
        /* Emit its second (if binary) or only (if unary) operand.  */
!       RETURN_IF_ERROR (result_append_char (dm, '('));
        RETURN_IF_ERROR (demangle_expression (dm));
!       RETURN_IF_ERROR (result_append_char (dm, ')'));
  
        /* The ternary operator takes a third operand.  */
        if (num_args == 3)
  	{
! 	  RETURN_IF_ERROR (result_append (dm, ":("));
  	  RETURN_IF_ERROR (demangle_expression (dm));
! 	  RETURN_IF_ERROR (result_append_char (dm, ')'));
  	}
      }
  
--- 3067,3096 ----
        /* If it's binary, do an operand first.  */
        if (num_args > 1)
  	{
! 	  status = result_add_char (dm, '(');
  	  if (STATUS_NO_ERROR (status))
  	    status = demangle_expression (dm);
  	  if (STATUS_NO_ERROR (status))
! 	    status = result_add_char (dm, ')');
  	}
  
        /* Emit the operator.  */  
        if (STATUS_NO_ERROR (status))
! 	status = result_add_string (dm, operator_name);
        dyn_string_delete (operator_name);
        RETURN_IF_ERROR (status);
        
        /* Emit its second (if binary) or only (if unary) operand.  */
!       RETURN_IF_ERROR (result_add_char (dm, '('));
        RETURN_IF_ERROR (demangle_expression (dm));
!       RETURN_IF_ERROR (result_add_char (dm, ')'));
  
        /* The ternary operator takes a third operand.  */
        if (num_args == 3)
  	{
! 	  RETURN_IF_ERROR (result_add (dm, ":("));
  	  RETURN_IF_ERROR (demangle_expression (dm));
! 	  RETURN_IF_ERROR (result_add_char (dm, ')'));
  	}
      }
  
*************** demangle_scope_expression (dm)
*** 3009,3015 ****
    RETURN_IF_ERROR (demangle_char (dm, 's'));
    RETURN_IF_ERROR (demangle_char (dm, 'r'));
    RETURN_IF_ERROR (demangle_type (dm));
!   RETURN_IF_ERROR (result_append (dm, "::"));
    RETURN_IF_ERROR (demangle_encoding (dm));
    return STATUS_OK;
  }
--- 3109,3115 ----
    RETURN_IF_ERROR (demangle_char (dm, 's'));
    RETURN_IF_ERROR (demangle_char (dm, 'r'));
    RETURN_IF_ERROR (demangle_type (dm));
!   RETURN_IF_ERROR (result_add (dm, "::"));
    RETURN_IF_ERROR (demangle_encoding (dm));
    return STATUS_OK;
  }
*************** demangle_substitution (dm, template_p)
*** 3100,3116 ****
        switch (peek)
  	{
  	case 't':
! 	  RETURN_IF_ERROR (result_append (dm, "std"));
  	  break;
  
  	case 'a':
! 	  RETURN_IF_ERROR (result_append (dm, "std::allocator"));
  	  new_last_source_name = "allocator";
  	  *template_p = 1;
  	  break;
  
  	case 'b':
! 	  RETURN_IF_ERROR (result_append (dm, "std::basic_string"));
  	  new_last_source_name = "basic_string";
  	  *template_p = 1;
  	  break;
--- 3200,3216 ----
        switch (peek)
  	{
  	case 't':
! 	  RETURN_IF_ERROR (result_add (dm, "std"));
  	  break;
  
  	case 'a':
! 	  RETURN_IF_ERROR (result_add (dm, "std::allocator"));
  	  new_last_source_name = "allocator";
  	  *template_p = 1;
  	  break;
  
  	case 'b':
! 	  RETURN_IF_ERROR (result_add (dm, "std::basic_string"));
  	  new_last_source_name = "basic_string";
  	  *template_p = 1;
  	  break;
*************** demangle_substitution (dm, template_p)
*** 3118,3129 ****
  	case 's':
  	  if (!flag_verbose)
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::string"));
  	      new_last_source_name = "string";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"));
  	      new_last_source_name = "basic_string";
  	    }
  	  *template_p = 0;
--- 3218,3229 ----
  	case 's':
  	  if (!flag_verbose)
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::string"));
  	      new_last_source_name = "string";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"));
  	      new_last_source_name = "basic_string";
  	    }
  	  *template_p = 0;
*************** demangle_substitution (dm, template_p)
*** 3132,3143 ****
  	case 'i':
  	  if (!flag_verbose)
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::istream"));
  	      new_last_source_name = "istream";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::basic_istream<char, std::char_traints<char> >"));
  	      new_last_source_name = "basic_istream";
  	    }
  	  *template_p = 0;
--- 3232,3243 ----
  	case 'i':
  	  if (!flag_verbose)
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::istream"));
  	      new_last_source_name = "istream";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::basic_istream<char, std::char_traints<char> >"));
  	      new_last_source_name = "basic_istream";
  	    }
  	  *template_p = 0;
*************** demangle_substitution (dm, template_p)
*** 3146,3157 ****
  	case 'o':
  	  if (!flag_verbose)
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::ostream"));
  	      new_last_source_name = "ostream";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::basic_ostream<char, std::char_traits<char> >"));
  	      new_last_source_name = "basic_ostream";
  	    }
  	  *template_p = 0;
--- 3246,3257 ----
  	case 'o':
  	  if (!flag_verbose)
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::ostream"));
  	      new_last_source_name = "ostream";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::basic_ostream<char, std::char_traits<char> >"));
  	      new_last_source_name = "basic_ostream";
  	    }
  	  *template_p = 0;
*************** demangle_substitution (dm, template_p)
*** 3160,3171 ****
  	case 'd':
  	  if (!flag_verbose) 
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::iostream"));
  	      new_last_source_name = "iostream";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_append (dm, "std::basic_iostream<char, std::char_traits<char> >"));
  	      new_last_source_name = "basic_iostream";
  	    }
  	  *template_p = 0;
--- 3260,3271 ----
  	case 'd':
  	  if (!flag_verbose) 
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::iostream"));
  	      new_last_source_name = "iostream";
  	    }
  	  else
  	    {
! 	      RETURN_IF_ERROR (result_add (dm, "std::basic_iostream<char, std::char_traits<char> >"));
  	      new_last_source_name = "basic_iostream";
  	    }
  	  *template_p = 0;
*************** demangle_substitution (dm, template_p)
*** 3196,3202 ****
      return "Substitution number out of range.";
  
    /* Emit the substitution text.  */
!   RETURN_IF_ERROR (result_append_string (dm, text));
  
    RETURN_IF_ERROR (demangle_char (dm, '_'));
    return STATUS_OK;
--- 3296,3302 ----
      return "Substitution number out of range.";
  
    /* Emit the substitution text.  */
!   RETURN_IF_ERROR (result_add_string (dm, text));
  
    RETURN_IF_ERROR (demangle_char (dm, '_'));
    return STATUS_OK;
*************** demangle_local_name (dm)
*** 3216,3227 ****
    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, "::"));
  
    if (peek_char (dm) == 's')
      {
        /* Local character string literal.  */
!       RETURN_IF_ERROR (result_append (dm, "string literal"));
        /* Consume the s.  */
        advance_char (dm);
        RETURN_IF_ERROR (demangle_discriminator (dm, 0));
--- 3316,3327 ----
    RETURN_IF_ERROR (demangle_char (dm, 'Z'));
    RETURN_IF_ERROR (demangle_encoding (dm));
    RETURN_IF_ERROR (demangle_char (dm, 'E'));
!   RETURN_IF_ERROR (result_add (dm, "::"));
  
    if (peek_char (dm) == 's')
      {
        /* Local character string literal.  */
!       RETURN_IF_ERROR (result_add (dm, "string literal"));
        /* Consume the s.  */
        advance_char (dm);
        RETURN_IF_ERROR (demangle_discriminator (dm, 0));
*************** demangle_discriminator (dm, suppress_fir
*** 3258,3264 ****
        /* Consume the underscore.  */
        advance_char (dm);
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_append (dm, " [#"));
        /* Check if there's a number following the underscore.  */
        if (IS_DIGIT ((unsigned char) peek_char (dm)))
  	{
--- 3358,3364 ----
        /* Consume the underscore.  */
        advance_char (dm);
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_add (dm, " [#"));
        /* Check if there's a number following the underscore.  */
        if (IS_DIGIT ((unsigned char) peek_char (dm)))
  	{
*************** demangle_discriminator (dm, suppress_fir
*** 3276,3290 ****
  	{
  	  if (flag_verbose)
  	    /* A missing digit correspond to one.  */
! 	    RETURN_IF_ERROR (result_append_char (dm, '1'));
  	}
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_append_char (dm, ']'));
      }
    else if (!suppress_first)
      {
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_append (dm, " [#0]"));
      }
  
    return STATUS_OK;
--- 3376,3390 ----
  	{
  	  if (flag_verbose)
  	    /* A missing digit correspond to one.  */
! 	    RETURN_IF_ERROR (result_add_char (dm, '1'));
  	}
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_add_char (dm, ']'));
      }
    else if (!suppress_first)
      {
        if (flag_verbose)
! 	RETURN_IF_ERROR (result_add (dm, " [#0]"));
      }
  
    return STATUS_OK;


More information about the Gcc-patches mailing list