Next round of new demangler patches

Ian Lance Taylor ian@airs.com
Sun Dec 7 03:01:00 GMT 2003


These patches to the new demangler fix two problems pointed out by
Michael Elizabeth Chastain.

The first problem is that when a constructor/destructor is defined for
a class which is itself a standard substitution, the demangler would
use the short name without the template arguments, which led to things
like std::string::~string(), which can be confusing since std::string
is an abbreviation for a specialization of basic_string<>, so the
actual function is named basic_string().

The second problem is simply that negative constants were not handle
correctly--the demangler printed 'n' instead of '-'.

This patch also causes the demangler to use the full template
expansion of a standard substitution when DMGL_VERBOSE is passed.
This is what the old version of the demangler did, and it makes sense
to me--at least, assuming that we want to give any meaning to
DMGL_VERBOSE at all.

Ian


2003-12-06  Ian Lance Taylor  <ian@wasabisystems.com>

	Fix handling of constructor/destructor of standard substitution:
	* cp-demangle.c (struct d_standard_sub_info): Define.
	(d_substitution): Add prefix argument.  Change all callers.
	Rework handling of standard substitutions to print full name when
	qualifying a constructor/destructor, or when DMGL_VERBOSE is set.
	* testsuite/demangle-expected: Add test case.

	Fix handling of negative literal constants:
	* cp-demangle.c (enum d_comp_type): Add D_COMP_LITERAL_NEG.
	(d_dump, d_make_comp): Handle D_COMP_LITERAL_NEG.
	(d_expr_primary): Use D_COMP_LITERAL_NEG for a negative number.
	(d_print_comp): Handle D_COMP_LITERAL_NEG.
	* testsuite/demangle-expected: Add test case.


Index: cp-demangle.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/cp-demangle.c,v
retrieving revision 1.57
diff -u -p -r1.57 cp-demangle.c
--- cp-demangle.c	4 Dec 2003 19:48:43 -0000	1.57
+++ cp-demangle.c	7 Dec 2003 02:50:35 -0000
@@ -141,6 +141,23 @@ struct d_builtin_type_info
   enum d_builtin_type_print print;
 };
 
+/* Information we keep for the standard substitutions.  */
+
+struct d_standard_sub_info
+{
+  /* The code for this substitution.  */
+  char code;
+  /* The simple string it expands to.  */
+  const char *simple_expansion;
+  /* The results of a full, verbose, expansion.  This is used when
+     qualifying a constructor/destructor, or when in verbose mode.  */
+  const char *full_expansion;
+  /* What to set the last_name field of d_info to; NULL if we should
+     not set it.  This is only relevant when qualifying a
+     constructor/destructor.  */
+  const char *set_last_name;
+};
+
 /* Component types found in mangled names.  */
 
 enum d_comp_type
@@ -239,7 +256,9 @@ enum d_comp_type
   D_COMP_TRINARY_ARG1,
   D_COMP_TRINARY_ARG2,
   /* A literal.  */
-  D_COMP_LITERAL
+  D_COMP_LITERAL,
+  /* A negative literal.  */
+  D_COMP_LITERAL_NEG
 };
 
 /* A component of the mangled name.  */
@@ -489,7 +508,7 @@ static struct d_comp *d_expr_primary PAR
 static struct d_comp *d_local_name PARAMS ((struct d_info *));
 static int d_discriminator PARAMS ((struct d_info *));
 static int d_add_substitution PARAMS ((struct d_info *, struct d_comp *));
-static struct d_comp *d_substitution PARAMS ((struct d_info *));
+static struct d_comp *d_substitution PARAMS ((struct d_info *, int));
 static void d_print_resize PARAMS ((struct d_print_info *, size_t));
 static void d_print_append_char PARAMS ((struct d_print_info *, int));
 static void d_print_append_buffer PARAMS ((struct d_print_info *, const char *,
@@ -683,6 +702,9 @@ d_dump (dc, indent)
     case D_COMP_LITERAL:
       printf ("literal\n");
       break;
+    case D_COMP_LITERAL_NEG:
+      printf ("negative literal\n");
+      break;
     }
 
   d_dump (d_left (dc), indent + 2);
@@ -737,6 +759,7 @@ d_make_comp (di, type, left, right)
     case D_COMP_TRINARY_ARG1:
     case D_COMP_TRINARY_ARG2:
     case D_COMP_LITERAL:
+    case D_COMP_LITERAL_NEG:
       if (left == NULL || right == NULL)
 	return NULL;
       break;
@@ -1087,7 +1110,7 @@ d_name (di)
 
 	if (d_peek_next_char (di) != 't')
 	  {
-	    dc = d_substitution (di);
+	    dc = d_substitution (di, 0);
 	    subst = 1;
 	  }
 	else
@@ -1202,7 +1225,7 @@ d_prefix (di)
 	  || peek == 'D')
 	dc = d_unqualified_name (di);
       else if (peek == 'S')
-	dc = d_substitution (di);
+	dc = d_substitution (di, 1);
       else if (peek == 'I')
 	{
 	  if (ret == NULL)
@@ -1776,7 +1799,7 @@ d_type (di)
 	    || peek_next == '_'
 	    || IS_UPPER (peek_next))
 	  {
-	    ret = d_substitution (di);
+	    ret = d_substitution (di, 0);
 	    /* The substituted name may have been a template name and
 	       may be followed by tepmlate args.  */
 	    if (d_peek_char (di) == 'I')
@@ -2254,6 +2277,7 @@ d_expr_primary (di)
   else
     {
       struct d_comp *type;
+      enum d_comp_type t;
       const char *s;
 
       type = d_type (di);
@@ -2269,11 +2293,16 @@ d_expr_primary (di)
 	 constant in any readable form anyhow.  We don't attempt to
 	 handle these cases.  */
 
+      t = D_COMP_LITERAL;
+      if (d_peek_char (di) == 'n')
+	{
+	  t = D_COMP_LITERAL_NEG;
+	  d_advance (di, 1);
+	}
       s = d_str (di);
       while (d_peek_char (di) != 'E')
 	d_advance (di, 1);
-      ret = d_make_comp (di, D_COMP_LITERAL, type,
-			 d_make_name (di, s, d_str (di) - s));
+      ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
     }
   if (d_next_char (di) != 'E')
     return NULL;
@@ -2363,11 +2392,39 @@ d_add_substitution (di, dc)
                   ::= Si
                   ::= So
                   ::= Sd
+
+   If PREFIX is non-zero, then this type is being used as a prefix in
+   a qualified name.  In this case, for the standard substitutions, we
+   need to check whether we are being used as a prefix for a
+   constructor or destructor, and return a full template name.
+   Otherwise we will get something like std::iostream::~iostream()
+   which does not correspond particularly well to any function which
+   actually appears in the source.
 */
 
+static const struct d_standard_sub_info standard_subs[] =
+{
+  { 't', "std", "std", NULL },
+  { 'a', "std::allocator", "std::allocator", "allocator" },
+  { 'b', "std::basic_string", "std::basic_string", "basic_string" },
+  { 's', "std::string",
+    "std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
+    "basic_string" },
+  { 'i', "std::istream",
+    "std::basic_istream<char, std::char_traits<char> >",
+    "basic_istream" },
+  { 'o', "std::ostream",
+    "std::basic_ostream<char, std::char_traits<char> >",
+    "basic_ostream" },
+  { 'd', "std::iostream",
+    "std::basic_iostream<char, std::char_traits<char> >",
+    "basic_iostream" }
+};
+
 static struct d_comp *
-d_substitution (di)
+d_substitution (di, prefix)
      struct d_info *di;
+     int prefix;
 {
   char c;
 
@@ -2404,31 +2461,36 @@ d_substitution (di)
     }
   else
     {
-      switch (c)
+      int verbose;
+      const struct d_standard_sub_info *p;
+      const struct d_standard_sub_info *pend;
+
+      verbose = (di->options & DMGL_VERBOSE) != 0;
+      if (! verbose && prefix)
 	{
-	case 't':
-	  return d_make_sub (di, "std");
-	case 'a':
-	  di->last_name = d_make_sub (di, "allocator");
-	  return d_make_sub (di, "std::allocator");
-	case 'b':
-	  di->last_name = d_make_sub (di, "basic_string");
-	  return d_make_sub (di, "std::basic_string");
-	case 's':
-	  di->last_name = d_make_sub (di, "string");
-	  return d_make_sub (di, "std::string");
-	case 'i':
-	  di->last_name = d_make_sub (di, "istream");
-	  return d_make_sub (di, "std::istream");
-	case 'o':
-	  di->last_name = d_make_sub (di, "ostream");
-	  return d_make_sub (di, "std::ostream");
-	case 'd':
-	  di->last_name = d_make_sub (di, "iostream");
-	  return d_make_sub (di, "std::iostream");
-	default:
-	  return NULL;
+	  char peek;
+
+	  peek = d_peek_char (di);
+	  if (peek == 'C' || peek == 'D')
+	    verbose = 1;
 	}
+
+      pend = (&standard_subs[0]
+	      + sizeof standard_subs / sizeof standard_subs[0]);
+      for (p = &standard_subs[0]; p < pend; ++p)
+	{
+	  if (c == p->code)
+	    {
+	      if (p->set_last_name != NULL)
+		di->last_name = d_make_sub (di, p->set_last_name);
+	      if (verbose)
+		return d_make_sub (di, p->full_expansion);
+	      else
+		return d_make_sub (di, p->simple_expansion);
+	    }
+	}
+
+      return NULL;
     }
 }
 
@@ -3031,6 +3093,7 @@ d_print_comp (dpi, dc)
       return;
 
     case D_COMP_LITERAL:
+    case D_COMP_LITERAL_NEG:
       /* For some builtin types, produce simpler output.  */
       if (d_left (dc)->type == D_COMP_BUILTIN_TYPE)
 	{
@@ -3039,6 +3102,8 @@ d_print_comp (dpi, dc)
 	    case D_PRINT_INT:
 	      if (d_right (dc)->type == D_COMP_NAME)
 		{
+		  if (dc->type == D_COMP_LITERAL_NEG)
+		    d_append_char (dpi, '-');
 		  d_print_comp (dpi, d_right (dc));
 		  return;
 		}
@@ -3047,6 +3112,8 @@ d_print_comp (dpi, dc)
 	    case D_PRINT_LONG:
 	      if (d_right (dc)->type == D_COMP_NAME)
 		{
+		  if (dc->type == D_COMP_LITERAL_NEG)
+		    d_append_char (dpi, '-');
 		  d_print_comp (dpi, d_right (dc));
 		  d_append_char (dpi, 'l');
 		  return;
@@ -3055,7 +3122,8 @@ d_print_comp (dpi, dc)
 
 	    case D_PRINT_BOOL:
 	      if (d_right (dc)->type == D_COMP_NAME
-		  && d_right (dc)->u.s_name.len == 1)
+		  && d_right (dc)->u.s_name.len == 1
+		  && dc->type == D_COMP_LITERAL)
 		{
 		  switch (d_right (dc)->u.s_name.s[0])
 		    {
@@ -3079,6 +3147,8 @@ d_print_comp (dpi, dc)
       d_append_char (dpi, '(');
       d_print_comp (dpi, d_left (dc));
       d_append_char (dpi, ')');
+      if (dc->type == D_COMP_LITERAL_NEG)
+	d_append_char (dpi, '-');
       d_print_comp (dpi, d_right (dc));
       return;
 
Index: testsuite/demangle-expected
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/testsuite/demangle-expected,v
retrieving revision 1.22
diff -u -p -r1.22 demangle-expected
--- testsuite/demangle-expected	4 Dec 2003 19:48:44 -0000	1.22
+++ testsuite/demangle-expected	7 Dec 2003 02:50:35 -0000
@@ -2905,7 +2905,17 @@ bool std::operator< <file_path, std::str
 --format=gnu-v3
 _Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE
 hairyfunc(int (* const (X::** (* restrict (* volatile*(Y::*)(int) const)(char*)) [2])(long) const) [3])
-# 
+#
+# Check that negative numbers are handled correctly.
+--format=gnu-v3
+_Z1fILin1EEvv
+void f<-1>()
+#
+# Check a destructor of a standard substitution.
+--format=gnu-v3
+_ZNSdD0Ev
+std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()
+#
 # This caused an infinite loop.
 #
 # This is generated by an EDG compiler (kcc 4.0).  To demangle it



More information about the Gcc-patches mailing list