merge from gcc
[binutils-gdb.git] / libiberty / cp-demangle.c
index a412e8878514b2653489e547bd028f8baca15a6d..e3ef42ce261d904efff4165091921331ddeb8268 100644 (file)
@@ -1,5 +1,5 @@
 /* Demangler for IA64 / g++ V3 ABI.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>. 
 
    This file is part of GNU CC.
@@ -9,6 +9,15 @@
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
+   In addition to the permissions in the GNU General Public License, the
+   Free Software Foundation gives you unlimited permission to link the
+   compiled version of this file into combinations with other programs,
+   and to distribute those combinations without any restriction coming
+   from the use of this file.  (The General Public License restrictions
+   do apply in other respects; for example, they cover modification of
+   the file, and distribution when not linked into a combined
+   executable.)
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -889,7 +898,7 @@ static status_t demangle_number_literally
 static status_t demangle_identifier
   PARAMS ((demangling_t, int, dyn_string_t));
 static status_t demangle_operator_name
-  PARAMS ((demangling_t, int, int *));
+  PARAMS ((demangling_t, int, int *, int *));
 static status_t demangle_nv_offset
   PARAMS ((demangling_t));
 static status_t demangle_v_offset
@@ -1316,7 +1325,7 @@ demangle_unqualified_name (dm, suppress_return_type)
       if (peek == 'c' && peek_char_next (dm) == 'v')
        *suppress_return_type = 1;
 
-      RETURN_IF_ERROR (demangle_operator_name (dm, 0, &num_args));
+      RETURN_IF_ERROR (demangle_operator_name (dm, 0, &num_args, NULL));
     }
   else if (peek == 'C' || peek == 'D')
     {
@@ -1492,7 +1501,9 @@ demangle_identifier (dm, length, identifier)
 /* Demangles and emits an <operator-name>.  If SHORT_NAME is non-zero,
    the short form is emitted; otherwise the full source form
    (`operator +' etc.) is emitted.  *NUM_ARGS is set to the number of
-   operands that the operator takes.  
+   operands that the operator takes.  If TYPE_ARG is non-NULL,
+   *TYPE_ARG is set to 1 if the first argument is a type and 0
+   otherwise.
 
     <operator-name>
                   ::= nw        # new           
@@ -1542,15 +1553,17 @@ demangle_identifier (dm, length, identifier)
                   ::= cl        # ()            
                   ::= ix        # []            
                   ::= qu        # ?
-                  ::= sz        # sizeof 
+                 ::= st        # sizeof (a type)
+                  ::= sz        # sizeof (an expression)
                   ::= cv <type> # cast        
                  ::= v [0-9] <source-name>  # vendor extended operator  */
 
 static status_t
-demangle_operator_name (dm, short_name, num_args)
+demangle_operator_name (dm, short_name, num_args, type_arg)
      demangling_t dm;
      int short_name;
      int *num_args;
+     int *type_arg;
 {
   struct operator_code
   {
@@ -1624,6 +1637,10 @@ demangle_operator_name (dm, short_name, num_args)
 
   DEMANGLE_TRACE ("operator-name", dm);
 
+  /* Assume the first argument is not a type.  */
+  if (type_arg)
+    *type_arg = 0;
+
   /* Is this a vendor-extended operator?  */
   if (c0 == 'v' && IS_DIGIT (c1))
     {
@@ -1643,6 +1660,16 @@ demangle_operator_name (dm, short_name, num_args)
       return STATUS_OK;
     }
 
+  /* Is it the sizeof variant that takes a type?  */
+  if (c0 == 's' && c1 == 't')
+    {
+      RETURN_IF_ERROR (result_add (dm, " sizeof"));
+      *num_args = 1;
+      if (type_arg)
+       *type_arg = 1;
+      return STATUS_OK;
+    }
+
   /* Perform a binary search for the operator code.  */
   while (1)
     {
@@ -3145,6 +3172,7 @@ demangle_expression (dm)
     /* An operator expression.  */
     {
       int num_args;
+      int type_arg;
       status_t status = STATUS_OK;
       dyn_string_t operator_name;
 
@@ -3152,7 +3180,8 @@ demangle_expression (dm)
         operations in infix notation, capture the operator name
         first.  */
       RETURN_IF_ERROR (result_push (dm));
-      RETURN_IF_ERROR (demangle_operator_name (dm, 1, &num_args));
+      RETURN_IF_ERROR (demangle_operator_name (dm, 1, &num_args,
+                                              &type_arg));
       operator_name = (dyn_string_t) result_pop (dm);
 
       /* If it's binary, do an operand first.  */
@@ -3173,7 +3202,10 @@ demangle_expression (dm)
       
       /* Emit its second (if binary) or only (if unary) operand.  */
       RETURN_IF_ERROR (result_add_char (dm, '('));
-      RETURN_IF_ERROR (demangle_expression (dm));
+      if (type_arg)
+       RETURN_IF_ERROR (demangle_type (dm));
+      else
+       RETURN_IF_ERROR (demangle_expression (dm));
       RETURN_IF_ERROR (result_add_char (dm, ')'));
 
       /* The ternary operator takes a third operand.  */
@@ -3537,7 +3569,7 @@ cp_demangle_type (type_name, result)
      dyn_string_t result;
 {
   status_t status;
-  demangling_t dm = demangling_new (type_name, 0);
+  demangling_t dm = demangling_new (type_name, DMGL_GNU_V3);
   
   if (dm == NULL)
     return STATUS_ALLOCATION_FAILED;
@@ -3568,7 +3600,7 @@ cp_demangle_type (type_name, result)
   return status;
 }
 
-#ifdef IN_LIBGCC2
+#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
 extern char *__cxa_demangle PARAMS ((const char *, char *, size_t *, int *));
 
 /* ia64 ABI-mandated entry point in the C++ runtime library for performing
@@ -3676,7 +3708,7 @@ __cxa_demangle (mangled_name, output_buffer, length, status)
     }
 }
 
-#else /* !IN_LIBGCC2 */
+#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */
 
 /* Variant entry point for integration with the existing cplus-dem
    demangler.  Attempts to demangle MANGLED.  If the demangling
@@ -3685,16 +3717,30 @@ __cxa_demangle (mangled_name, output_buffer, length, status)
    If the demangling failes, returns NULL.  */
 
 char *
-cplus_demangle_v3 (mangled)
+cplus_demangle_v3 (mangled, options)
      const char* mangled;
+     int options;
 {
   dyn_string_t demangled;
   status_t status;
+  int type = !!(options & DMGL_TYPES);
+
+  if (mangled[0] == '_' && mangled[1] == 'Z')
+    /* It is not a type.  */
+    type = 0;
+  else
+    {
+      /* It is a type. Stop if we don't want to demangle types. */
+      if (!type)
+       return NULL;
+    }
+
+  flag_verbose = !!(options & DMGL_VERBOSE);
 
   /* Create a dyn_string to hold the demangled name.  */
   demangled = dyn_string_new (0);
   /* Attempt the demangling.  */
-  if (mangled[0] == '_' && mangled[1] == 'Z')
+  if (!type)
     /* Appears to be a function or variable name.  */
     status = cp_demangle (mangled, demangled, 0);
   else
@@ -3823,13 +3869,18 @@ java_demangle_v3 (mangled)
 
   free (cplus_demangled);
   
-  return_value = dyn_string_release (demangled);
+  if (demangled)
+    return_value = dyn_string_release (demangled);
+  else
+    return_value = NULL;
+
   return return_value;
 }
 
-#endif /* IN_LIBGCC2 */
+#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */
 
 
+#ifndef IN_GLIBCPP_V3
 /* Demangle NAME in the G++ V3 ABI demangling style, and return either
    zero, indicating that some error occurred, or a demangling_t
    holding the results.  */
@@ -3909,6 +3960,7 @@ is_gnu_v3_mangled_dtor (name)
   else
     return 0;
 }
+#endif /* IN_GLIBCPP_V3 */
 
 
 #ifdef STANDALONE_DEMANGLER