PR c++/12266
[deliverable/binutils-gdb.git] / gdb / cp-support.c
index a4790671894e34b7aa05e0da0d72313ad140b946..9e001b2f94a364dff1b9c0c575e1544b208f5cde 100644 (file)
@@ -86,6 +86,47 @@ static const char *operator_tokens[] =
     /* new[] and delete[] require special whitespace handling */
   };
 
+/* A list of typedefs which should not be substituted by replace_typedefs.  */
+static const char * const ignore_typedefs[] =
+  {
+    "std::istream", "std::iostream", "std::ostream", "std::string"
+  };
+
+static void
+  replace_typedefs (struct demangle_parse_info *info,
+                   struct demangle_component *ret_comp);
+
+/* A convenience function to copy STRING into OBSTACK, returning a pointer
+   to the newly allocated string and saving the number of bytes saved in LEN.
+
+   It does not copy the terminating '\0' byte!  */
+
+static char *
+copy_string_to_obstack (struct obstack *obstack, const char *string,
+                       long *len)
+{
+  *len = strlen (string);
+  return obstack_copy (obstack, string, *len);
+}
+
+/* A cleanup wrapper for cp_demangled_name_parse_free.  */
+
+static void
+do_demangled_name_parse_free_cleanup (void *data)
+{
+  struct demangle_parse_info *info = (struct demangle_parse_info *) data;
+
+  cp_demangled_name_parse_free (info);
+}
+
+/* Create a cleanup for C++ name parsing.  */
+
+struct cleanup *
+make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *info)
+{
+  return make_cleanup (do_demangled_name_parse_free_cleanup, info);
+}
+
 /* Return 1 if STRING is clearly already in canonical form.  This
    function is conservative; things which it does not recognize are
    assumed to be non-canonical, and the parser will sort them out
@@ -117,6 +158,355 @@ cp_already_canonical (const char *string)
     return 0;
 }
 
+/* Inspect the given RET_COMP for its type.  If it is a typedef,
+   replace the node with the typedef's tree.
+
+   Returns 1 if any typedef substitutions were made, 0 otherwise.  */
+
+static int
+inspect_type (struct demangle_parse_info *info,
+             struct demangle_component *ret_comp)
+{
+  int i;
+  char *name;
+  struct symbol *sym;
+  volatile struct gdb_exception except;
+
+  /* Copy the symbol's name from RET_COMP and look it up
+     in the symbol table.  */
+  name = (char *) alloca (ret_comp->u.s_name.len + 1);
+  memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
+  name[ret_comp->u.s_name.len] = '\0';
+
+  /* Ignore any typedefs that should not be substituted.  */
+  for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+    {
+      if (strcmp (name, ignore_typedefs[i]) == 0)
+       return 0;
+    }
+
+  sym = NULL;
+  TRY_CATCH (except, RETURN_MASK_ALL)
+  {
+    sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+  }
+
+  if (except.reason >= 0 && sym != NULL)
+    {
+      struct type *otype = SYMBOL_TYPE (sym);
+
+      /* If the type is a typedef, replace it.  */
+      if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
+       {
+         long len;
+         int is_anon;
+         struct type *type;
+         struct demangle_parse_info *i;
+         struct ui_file *buf;
+
+         /* Get the real type of the typedef.  */
+         type = check_typedef (otype);
+
+         is_anon = (TYPE_TAG_NAME (type) == NULL
+                    && (TYPE_CODE (type) == TYPE_CODE_ENUM
+                        || TYPE_CODE (type) == TYPE_CODE_STRUCT
+                        || TYPE_CODE (type) == TYPE_CODE_UNION));
+         if (is_anon)
+           {
+             struct type *last = otype;
+
+             /* Find the last typedef for the type.  */
+             while (TYPE_TARGET_TYPE (last) != NULL
+                    && (TYPE_CODE (TYPE_TARGET_TYPE (last))
+                        == TYPE_CODE_TYPEDEF))
+               last = TYPE_TARGET_TYPE (last);
+
+             /* If there is only one typedef for this anonymous type,
+                do not substitute it.  */
+             if (type == otype)
+               return 0;
+             else
+               /* Use the last typedef seen as the type for this
+                  anonymous type.  */
+               type = last;
+           }
+
+         buf = mem_fileopen ();
+         TRY_CATCH (except, RETURN_MASK_ERROR)
+         {
+           type_print (type, "", buf, -1);
+         }
+
+         /* If type_print threw an exception, there is little point
+            in continuing, so just bow out gracefully.  */
+         if (except.reason < 0)
+           {
+             ui_file_delete (buf);
+             return 0;
+           }
+
+         name = ui_file_obsavestring (buf, &info->obstack, &len);
+         ui_file_delete (buf);
+
+         /* Turn the result into a new tree.  Note that this
+            tree will contain pointers into NAME, so NAME cannot
+            be free'd until all typedef conversion is done and
+            the final result is converted into a string.  */
+         i = cp_demangled_name_to_comp (name, NULL);
+         if (i != NULL)
+           {
+             /* Merge the two trees.  */
+             cp_merge_demangle_parse_infos (info, ret_comp, i);
+
+             /* Replace any newly introduced typedefs -- but not
+                if the type is anonymous (that would lead to infinite
+                looping).  */
+             if (!is_anon)
+               replace_typedefs (info, ret_comp);
+           }
+         else
+           {
+             /* This shouldn't happen unless the type printer has
+                output something that the name parser cannot grok.
+                Nonetheless, an ounce of prevention...
+
+                Canonicalize the name again, and store it in the
+                current node (RET_COMP).  */
+             char *canon = cp_canonicalize_string_no_typedefs (name);
+
+             if (canon != NULL)
+               {
+                 /* Copy the canonicalization into the obstack and
+                    free CANON.  */
+                 name = copy_string_to_obstack (&info->obstack, canon, &len);
+                 xfree (canon);
+               }
+
+             ret_comp->u.s_name.s = name;
+             ret_comp->u.s_name.len = len;
+           }
+
+         return 1;
+       }
+    }
+
+  return 0;
+}
+
+/* Replace any typedefs appearing in the qualified name
+   (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+   given in INFO.  */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+                                struct demangle_component *ret_comp)
+{
+  long len;
+  char *name;
+  struct ui_file *buf = mem_fileopen ();
+  struct demangle_component *comp = ret_comp;
+
+  /* Walk each node of the qualified name, reconstructing the name of
+     this element.  With every node, check for any typedef substitutions.
+     If a substitution has occurred, replace the qualified name node
+     with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
+     substituted name.  */
+  while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+    {
+      if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
+       {
+         struct demangle_component new;
+
+         ui_file_write (buf, d_left (comp)->u.s_name.s,
+                        d_left (comp)->u.s_name.len);
+         name = ui_file_obsavestring (buf, &info->obstack, &len);
+         new.type = DEMANGLE_COMPONENT_NAME;
+         new.u.s_name.s = name;
+         new.u.s_name.len = len;
+         if (inspect_type (info, &new))
+           {
+             char *n, *s;
+             long slen;
+
+             /* A typedef was substituted in NEW.  Convert it to a
+                string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
+                node.  */
+
+             ui_file_rewind (buf);
+             n = cp_comp_to_string (&new, 100);
+             if (n == NULL)
+               {
+                 /* If something went astray, abort typedef substitutions.  */
+                 ui_file_delete (buf);
+                 return;
+               }
+
+             s = copy_string_to_obstack (&info->obstack, n, &slen);
+             xfree (n);
+
+             d_left (ret_comp)->type = DEMANGLE_COMPONENT_NAME;
+             d_left (ret_comp)->u.s_name.s = s;
+             d_left (ret_comp)->u.s_name.len = slen;
+             d_right (ret_comp) = d_right (comp);
+             comp = ret_comp;
+             continue;
+           }
+       }
+      else
+       {
+         /* The current node is not a name, so simply replace any
+            typedefs in it.  Then print it to the stream to continue
+            checking for more typedefs in the tree.  */
+         replace_typedefs (info, d_left (comp));
+         name = cp_comp_to_string (d_left (comp), 100);
+         if (name == NULL)
+           {
+             /* If something went astray, abort typedef substitutions.  */
+             ui_file_delete (buf);
+             return;
+           }
+         fputs_unfiltered (name, buf);
+         xfree (name);
+       }
+      ui_file_write (buf, "::", 2);
+      comp = d_right (comp);
+    }
+
+  /* If the next component is DEMANGLE_COMPONENT_NAME, save the qualified
+     name assembled above and append the name given by COMP.  Then use this
+     reassembled name to check for a typedef.  */
+
+  if (comp->type == DEMANGLE_COMPONENT_NAME)
+    {
+      ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+      name = ui_file_obsavestring (buf, &info->obstack, &len);
+
+      /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node
+        with a DEMANGLE_COMPONENT_NAME node containing the whole
+        name.  */
+      ret_comp->type = DEMANGLE_COMPONENT_NAME;
+      ret_comp->u.s_name.s = name;
+      ret_comp->u.s_name.len = len;
+      inspect_type (info, ret_comp);
+    }
+  else
+    replace_typedefs (info, comp);
+
+  ui_file_delete (buf);
+}
+
+
+/* A function to check const and volatile qualifiers for argument types.
+
+   "Parameter declarations that differ only in the presence
+   or absence of `const' and/or `volatile' are equivalent."
+   C++ Standard N3290, clause 13.1.3 #4.  */
+
+static void
+check_cv_qualifiers (struct demangle_component *ret_comp)
+{
+  while (d_left (ret_comp) != NULL
+        && (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST
+            || d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE))
+    {
+      d_left (ret_comp) = d_left (d_left (ret_comp));
+    }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+   their basic types.  */
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+                 struct demangle_component *ret_comp)
+{
+  if (ret_comp)
+    {
+      switch (ret_comp->type)
+       {
+       case DEMANGLE_COMPONENT_ARGLIST:
+         check_cv_qualifiers (ret_comp);
+         /* Fall through */
+
+       case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+       case DEMANGLE_COMPONENT_TEMPLATE:
+       case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+       case DEMANGLE_COMPONENT_TYPED_NAME:
+         replace_typedefs (info, d_left (ret_comp));
+         replace_typedefs (info, d_right (ret_comp));
+         break;
+
+       case DEMANGLE_COMPONENT_NAME:
+         inspect_type (info, ret_comp);
+         break;
+
+       case DEMANGLE_COMPONENT_QUAL_NAME:
+         replace_typedefs_qualified_name (info, ret_comp);
+         break;
+
+       case DEMANGLE_COMPONENT_LOCAL_NAME:
+       case DEMANGLE_COMPONENT_CTOR:
+       case DEMANGLE_COMPONENT_ARRAY_TYPE:
+       case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+         replace_typedefs (info, d_right (ret_comp));
+         break;
+
+       case DEMANGLE_COMPONENT_CONST:
+       case DEMANGLE_COMPONENT_RESTRICT:
+       case DEMANGLE_COMPONENT_VOLATILE:
+       case DEMANGLE_COMPONENT_VOLATILE_THIS:
+       case DEMANGLE_COMPONENT_CONST_THIS:
+       case DEMANGLE_COMPONENT_RESTRICT_THIS:
+       case DEMANGLE_COMPONENT_POINTER:
+       case DEMANGLE_COMPONENT_REFERENCE:
+         replace_typedefs (info, d_left (ret_comp));
+         break;
+
+       default:
+         break;
+       }
+    }
+}
+
+/* Parse STRING and convert it to canonical form, resolving any typedefs.
+   If parsing fails, or if STRING is already canonical, return NULL.
+   Otherwise return the canonical form.  The return value is allocated via
+   xmalloc.  */
+
+char *
+cp_canonicalize_string_no_typedefs (const char *string)
+{
+  char *ret;
+  unsigned int estimated_len;
+  struct demangle_parse_info *info;
+
+  ret = NULL;
+  estimated_len = strlen (string) * 2;
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info != NULL)
+    {
+      /* Replace all the typedefs in the tree.  */
+      replace_typedefs (info, info->tree);
+
+      /* Convert the tree back into a string.  */
+      ret = cp_comp_to_string (info->tree, estimated_len);
+      gdb_assert (ret != NULL);
+
+      /* Free the parse information.  */
+      cp_demangled_name_parse_free (info);
+
+      /* Finally, compare the original string with the computed
+        name, returning NULL if they are the same.  */
+      if (strcmp (string, ret) == 0)
+       {
+         xfree (ret);
+         return NULL;
+       }
+    }
+
+  return ret;
+}
+
 /* Parse STRING and convert it to canonical form.  If parsing fails,
    or if STRING is already canonical, return NULL.  Otherwise return
    the canonical form.  The return value is allocated via xmalloc.  */
@@ -124,19 +514,20 @@ cp_already_canonical (const char *string)
 char *
 cp_canonicalize_string (const char *string)
 {
-  struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   unsigned int estimated_len;
   char *ret;
 
   if (cp_already_canonical (string))
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (string, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info == NULL)
     return NULL;
 
   estimated_len = strlen (string) * 2;
-  ret = cp_comp_to_string (ret_comp, estimated_len);
+  ret = cp_comp_to_string (info->tree, estimated_len);
+  cp_demangled_name_parse_free (info);
 
   if (strcmp (string, ret) == 0)
     {
@@ -153,23 +544,27 @@ cp_canonicalize_string (const char *string)
    freed when finished with the tree, or NULL if none was needed.
    OPTIONS will be passed to the demangler.  */
 
-static struct demangle_component *
+static struct demangle_parse_info *
 mangled_name_to_comp (const char *mangled_name, int options,
                      void **memory, char **demangled_p)
 {
-  struct demangle_component *ret;
   char *demangled_name;
+  struct demangle_parse_info *info;
 
   /* If it looks like a v3 mangled name, then try to go directly
      to trees.  */
   if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
     {
+      struct demangle_component *ret;
+
       ret = cplus_demangle_v3_components (mangled_name,
                                          options, memory);
       if (ret)
        {
+         info = cp_new_demangle_parse_info ();
+         info->tree = ret;
          *demangled_p = NULL;
-         return ret;
+         return info;
        }
     }
 
@@ -181,16 +576,16 @@ mangled_name_to_comp (const char *mangled_name, int options,
   
   /* If we could demangle the name, parse it to build the component
      tree.  */
-  ret = cp_demangled_name_to_comp (demangled_name, NULL);
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
 
-  if (ret == NULL)
+  if (info == NULL)
     {
       xfree (demangled_name);
       return NULL;
     }
 
   *demangled_p = demangled_name;
-  return ret;
+  return info;
 }
 
 /* Return the name of the class containing method PHYSNAME.  */
@@ -201,14 +596,16 @@ cp_class_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp, *prev_comp, *cur_comp;
+  struct demangle_parse_info *info;
   int done;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-                                  &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+                              &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
   done = 0;
+  ret_comp = info->tree;
 
   /* First strip off any qualifiers, if we have a function or
      method.  */
@@ -277,8 +674,8 @@ cp_class_name_from_physname (const char *physname)
     }
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -348,13 +745,14 @@ method_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-                                  &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+                              &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
@@ -363,8 +761,8 @@ method_name_from_physname (const char *physname)
     ret = cp_comp_to_string (ret_comp, 10);
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -379,17 +777,19 @@ cp_func_name (const char *full_name)
 {
   char *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = cp_demangled_name_to_comp (full_name, NULL);
-  if (!ret_comp)
+  info = cp_demangled_name_to_comp (full_name, NULL);
+  if (!info)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
     ret = cp_comp_to_string (ret_comp, 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -402,16 +802,18 @@ cp_remove_params (const char *demangled_name)
 {
   int done = 0;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   char *ret = NULL;
 
   if (demangled_name == NULL)
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (demangled_name, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
+  if (info == NULL)
     return NULL;
 
   /* First strip off any qualifiers, if we have a function or method.  */
+  ret_comp = info->tree;
   while (!done)
     switch (ret_comp->type)
       {
@@ -433,6 +835,7 @@ cp_remove_params (const char *demangled_name)
   if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
     ret = cp_comp_to_string (d_left (ret_comp), 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
This page took 0.031376 seconds and 4 git commands to generate.