This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: Improvements to libiberty v3 demangler


Here are some patches which improve the libiberty v3 demangler.  These
mostly improve the handling of CV qualifiers.  Previously these would
tend to appear at the end of the string.  This patch attempts to put
them in the right place.  This fixes some of the errors caught by the
testsuite, and does not introduce any new errors.

After getting this far, I've realized that the whole approach used by
this code is fundamentally broken.  Thie approach taken by this code
can not handle substitutions correctly, because demangling pointers
and references to substitutions, to say nothing of qualifiers,
requires knowing the structure of the substitution source, and this
code does not have that information.

Still, this patch is an improvement over what is there now, and does
fix some bugs.

Ian


2003-11-18  Ian Lance Taylor  <ian@wasabisystems.com>

	* cp-demangle.c (demangle_operator_name): Remove space before
	"sizeof".
	(demangle_type_ptr): Put qualifiers in the right place.  Handle
	qualifiers in pointer to member specially.
	(demangle_type): Handle qualifiers for pointer or reference
	specially.  Handle function type.
	(demangle_local_name): Save and restore caret around demangling of
	initial encoding.


Index: cp-demangle.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/cp-demangle.c,v
retrieving revision 1.48
diff -u -p -r1.48 cp-demangle.c
--- cp-demangle.c	12 Aug 2003 06:58:17 -0000	1.48
+++ cp-demangle.c	19 Nov 2003 03:15:21 -0000
@@ -1147,7 +1147,7 @@ demangle_name (dm, encode_return_type)
 
 /* Demangles and emits a <nested-name>. 
 
-    <nested-name>     ::= N [<CV-qualifiers>] <prefix> <unqulified-name> E  */
+    <nested-name>     ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E  */
 
 static status_t
 demangle_nested_name (dm, encode_return_type)
@@ -1662,7 +1662,7 @@ demangle_operator_name (dm, short_name, 
     { "rS", ">>="      , 2 },
     { "rm", "%"        , 2 },
     { "rs", ">>"       , 2 },
-    { "sz", " sizeof"  , 1 }
+    { "sz", "sizeof"  , 1 }
   };
 
   const int num_operators = 
@@ -2236,6 +2236,9 @@ demangle_type_ptr (dm, insert_pos, subst
     {
       /* A pointer-to-member.  */
       dyn_string_t class_type;
+      char peek;
+      int reset_caret = 0;
+      int old_caret_position;
       
       /* Eat the 'M'.  */
       advance_char (dm);
@@ -2245,14 +2248,43 @@ demangle_type_ptr (dm, insert_pos, subst
       RETURN_IF_ERROR (demangle_type (dm));
       class_type = (dyn_string_t) result_pop (dm);
       
-      if (peek_char (dm) == 'F')
+      peek = peek_char (dm);
+      old_caret_position = result_get_caret (dm);
+      if (peek == 'r' || peek == 'V' || peek == 'K')
+	{
+	  dyn_string_t cv_qualifiers = dyn_string_new (24);
+	  status_t status;
+
+	  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));
+
+	  dyn_string_delete (cv_qualifiers);
+	  RETURN_IF_ERROR (status);
+	  /* Prepend a blank.  */
+	  RETURN_IF_ERROR (result_add_char (dm, ' '));
+	  result_shift_caret (dm, -1);
+
+	  peek = peek_char (dm);
+	  reset_caret = 1;
+	}
+
+      if (peek == '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 if (peek_char (dm) == 'A')
+      else if (peek == '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
@@ -2286,6 +2318,9 @@ demangle_type_ptr (dm, insert_pos, subst
       /* Clean up. */
       dyn_string_delete (class_type);
 
+      if (reset_caret)
+	result_set_caret (dm, old_caret_position);
+
       RETURN_IF_ERROR (status);
     }
     break;
@@ -2317,6 +2352,39 @@ demangle_type_ptr (dm, insert_pos, subst
       RETURN_IF_ERROR (demangle_array_type (dm, insert_pos));
       break;
 
+    case 'r':
+    case 'V':
+    case 'K':
+      /* Qualified base type.  Pick up the qualifiers.  */
+      {
+	dyn_string_t cv_qualifiers = dyn_string_new (24);
+
+	if (cv_qualifiers == NULL)
+	  return STATUS_ALLOCATION_FAILED;
+
+	/* Pick up all adjacent CV qualifiers.  */
+	demangle_CV_qualifiers (dm, cv_qualifiers);
+
+	/* Demangle the underlying type.  */
+	status = demangle_type_ptr (dm, insert_pos, substitution_start);
+
+	/* Insert the qualifiers where we're told to.  */
+	if (STATUS_NO_ERROR (status))
+	  {
+	    status = result_insert_char (dm, *insert_pos, ' ');
+	    ++(*insert_pos);
+	    if (STATUS_NO_ERROR (status))
+	      status = result_insert_string (dm, *insert_pos, cv_qualifiers);
+	  }
+
+	/* The next character should go after the qualifiers.  */
+	*insert_pos += dyn_string_length (cv_qualifiers);
+
+	dyn_string_delete (cv_qualifiers);
+	RETURN_IF_ERROR (status);
+      }
+      break;
+
     default:
       /* No more pointer or reference tokens; this is therefore a
 	 pointer to data.  Finish up by demangling the underlying
@@ -2404,28 +2472,58 @@ demangle_type (dm)
 
 	  /* 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));
+	  /* If the underlying type is a pointer or reference type, we
+	     need to call demangle_type_ptr to find out where to put
+	     the qualifiers.  */
+	  peek = peek_char (dm);
+	  if (peek == 'P' || peek == 'R' || peek == 'M')
+	    {
+	      status = demangle_type_ptr (dm, &insert_pos,
+					  substitution_start (dm));
+	      if (STATUS_NO_ERROR (status))
+		{
+		  status = result_insert_char (dm, insert_pos, ' ');
+		  if (STATUS_NO_ERROR (status))
+		    status = result_insert_string (dm, insert_pos + 1,
+						   cv_qualifiers);
+		}
+	      dyn_string_delete (cv_qualifiers);
+	      RETURN_IF_ERROR (status);
+	    }
+	  else
+	    {
+	      /* Emit the qualifiers, and shift the caret left so that
+		 the underlying type will be emitted first.  */
+	      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);
 
-	  /* Put the caret back where it was previously.  */
-	  result_set_caret (dm, old_caret_position);
+	      /* 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;
 
       case 'F':
-	return "Non-pointer or -reference function type.";
+	/* The return type should go at the current position.  */
+	insert_pos = result_caret_pos (dm);
+	/* Put in parentheses to indicate that this is a function.  */
+	RETURN_IF_ERROR (result_add (dm, "()"));
+	/* 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));
+	break;
 
       case 'A':
 	RETURN_IF_ERROR (demangle_array_type (dm, NULL));
@@ -3472,10 +3570,17 @@ static status_t
 demangle_local_name (dm)
      demangling_t dm;
 {
+  int old_caret_position = result_get_caret (dm);
+
   DEMANGLE_TRACE ("local-name", dm);
 
   RETURN_IF_ERROR (demangle_char (dm, 'Z'));
   RETURN_IF_ERROR (demangle_encoding (dm));
+
+  /* Restore the caret to avoid being confused by any qualifiers we
+     may have found during the encoding.  */
+  result_set_caret (dm, old_caret_position);
+
   RETURN_IF_ERROR (demangle_char (dm, 'E'));
   RETURN_IF_ERROR (result_add (dm, "::"));
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]