Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy
[deliverable/binutils-gdb.git] / gdb / cp-support.c
index c31fcff1408d6dbbc471b27402fc781066c0d80f..1b0900e489f1361b62a6d7528af9501da16da379 100644 (file)
@@ -1,6 +1,5 @@
 /* Helper routines for C++ support in GDB.
-   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2002-2017 Free Software Foundation, Inc.
 
    Contributed by MontaVista Software.
 
@@ -21,9 +20,7 @@
 
 #include "defs.h"
 #include "cp-support.h"
-#include "gdb_string.h"
 #include "demangle.h"
-#include "gdb_assert.h"
 #include "gdbcmd.h"
 #include "dictionary.h"
 #include "objfiles.h"
 #include "block.h"
 #include "complaints.h"
 #include "gdbtypes.h"
-#include "exceptions.h"
 #include "expression.h"
 #include "value.h"
-
+#include "cp-abi.h"
+#include "namespace.h"
+#include <signal.h>
+#include "gdb_setjmp.h"
 #include "safe-ctype.h"
 
 #define d_left(dc) (dc)->u.s_binary.left
@@ -50,7 +49,7 @@ static void demangled_name_complaint (const char *name);
 
 /* Functions/variables related to overload resolution.  */
 
-static int sym_return_val_size;
+static int sym_return_val_size = -1;
 static int sym_return_val_index;
 static struct symbol **sym_return_val;
 
@@ -58,12 +57,10 @@ static void overload_list_add_symbol (struct symbol *sym,
                                      const char *oload_name);
 
 static void make_symbol_overload_list_using (const char *func_name,
-                                            const char *namespace);
+                                            const char *the_namespace);
 
 static void make_symbol_overload_list_qualified (const char *func_name);
 
-static void read_in_psymtabs (const char *oload_name);
-
 /* The list of "maint cplus" commands.  */
 
 struct cmd_list_element *maint_cplus_cmd_list = NULL;
@@ -73,18 +70,31 @@ struct cmd_list_element *maint_cplus_cmd_list = NULL;
 static void maint_cplus_command (char *arg, int from_tty);
 static void first_component_command (char *arg, int from_tty);
 
-/* Operator validation.
-   NOTE: Multi-byte operators (usually the assignment variety operator)
-   must appear before the single byte version, i.e., "+=" before "+".  */
-static const char *operator_tokens[] =
+/* A list of typedefs which should not be substituted by replace_typedefs.  */
+static const char * const ignore_typedefs[] =
   {
-    "++", "+=", "+", "->*", "->", "--", "-=", "-", "*=", "*", "/=", "/",
-    "%=", "%", "!=", "==", "!", "&&", "<<=", "<<", ">>=", ">>",
-    "<=", "<", ">=", ">", "~", "&=", "&", "|=", "||", "|", "^=", "^",
-    "=", "()", "[]", ",", "new", "delete"
-    /* new[] and delete[] require special whitespace handling */
+    "std::istream", "std::iostream", "std::ostream", "std::string"
   };
 
+static void
+  replace_typedefs (struct demangle_parse_info *info,
+                   struct demangle_component *ret_comp,
+                   canonicalization_ftype *finder,
+                   void *data);
+
+/* 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 (char *) obstack_copy (obstack, string, *len);
+}
+
 /* 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
@@ -116,78 +126,508 @@ 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,
+             canonicalization_ftype *finder,
+             void *data)
+{
+  int i;
+  char *name;
+  struct symbol *sym;
+
+  /* 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
+    {
+      sym = lookup_symbol (name, 0, VAR_DOMAIN, 0).symbol;
+    }
+  CATCH (except, RETURN_MASK_ALL)
+    {
+      return 0;
+    }
+  END_CATCH
+
+  if (sym != NULL)
+    {
+      struct type *otype = SYMBOL_TYPE (sym);
+
+      if (finder != NULL)
+       {
+         const char *new_name = (*finder) (otype, data);
+
+         if (new_name != NULL)
+           {
+             ret_comp->u.s_name.s = new_name;
+             ret_comp->u.s_name.len = strlen (new_name);
+             return 1;
+           }
+
+         return 0;
+       }
+
+      /* If the type is a typedef or namespace alias, replace it.  */
+      if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF
+         || TYPE_CODE (otype) == TYPE_CODE_NAMESPACE)
+       {
+         long len;
+         int is_anon;
+         struct type *type;
+         std::unique_ptr<demangle_parse_info> i;
+
+         /* Get the real type of the typedef.  */
+         type = check_typedef (otype);
+
+         /* If the symbol is a namespace and its type name is no different
+            than the name we looked up, this symbol is not a namespace
+            alias and does not need to be substituted.  */
+         if (TYPE_CODE (otype) == TYPE_CODE_NAMESPACE
+             && strcmp (TYPE_NAME (type), name) == 0)
+           return 0;
+
+         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;
+           }
+
+         string_file buf;
+         TRY
+           {
+             type_print (type, "", &buf, -1);
+           }
+         /* If type_print threw an exception, there is little point
+            in continuing, so just bow out gracefully.  */
+         CATCH (except, RETURN_MASK_ERROR)
+           {
+             return 0;
+           }
+         END_CATCH
+
+         len = buf.size ();
+         name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
+
+         /* 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.get ());
+
+             /* 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, finder, data);
+           }
+         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).  */
+             std::string canon = cp_canonicalize_string_no_typedefs (name);
+
+             if (!canon.empty ())
+               {
+                 /* Copy the canonicalization into the obstack.  */
+                 name = copy_string_to_obstack (&info->obstack, canon.c_str (), &len);
+               }
+
+             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,
+                                canonicalization_ftype *finder,
+                                void *data)
+{
+  long len;
+  char *name;
+  string_file buf;
+  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 newobj;
+
+         buf.write (d_left (comp)->u.s_name.s, d_left (comp)->u.s_name.len);
+         len = buf.size ();
+         name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
+         newobj.type = DEMANGLE_COMPONENT_NAME;
+         newobj.u.s_name.s = name;
+         newobj.u.s_name.len = len;
+         if (inspect_type (info, &newobj, finder, data))
+           {
+             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.  */
+
+             buf.clear ();
+             n = cp_comp_to_string (&newobj, 100);
+             if (n == NULL)
+               {
+                 /* If something went astray, abort typedef substitutions.  */
+                 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), finder, data);
+         name = cp_comp_to_string (d_left (comp), 100);
+         if (name == NULL)
+           {
+             /* If something went astray, abort typedef substitutions.  */
+             return;
+           }
+         buf.puts (name);
+         xfree (name);
+       }
+
+      buf.write ("::", 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)
+    {
+      buf.write (comp->u.s_name.s, comp->u.s_name.len);
+      len = buf.size ();
+      name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), 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, finder, data);
+    }
+  else
+    replace_typedefs (info, comp, finder, data);
+}
+
+
+/* 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,
+                 canonicalization_ftype *finder,
+                 void *data)
+{
+  if (ret_comp)
+    {
+      if (finder != NULL
+         && (ret_comp->type == DEMANGLE_COMPONENT_NAME
+             || ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME
+             || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE
+             || ret_comp->type == DEMANGLE_COMPONENT_BUILTIN_TYPE))
+       {
+         char *local_name = cp_comp_to_string (ret_comp, 10);
+
+         if (local_name != NULL)
+           {
+             struct symbol *sym = NULL;
+
+             sym = NULL;
+             TRY
+               {
+                 sym = lookup_symbol (local_name, 0, VAR_DOMAIN, 0).symbol;
+               }
+             CATCH (except, RETURN_MASK_ALL)
+               {
+               }
+             END_CATCH
+
+             xfree (local_name);
+
+             if (sym != NULL)
+               {
+                 struct type *otype = SYMBOL_TYPE (sym);
+                 const char *new_name = (*finder) (otype, data);
+
+                 if (new_name != NULL)
+                   {
+                     ret_comp->type = DEMANGLE_COMPONENT_NAME;
+                     ret_comp->u.s_name.s = new_name;
+                     ret_comp->u.s_name.len = strlen (new_name);
+                     return;
+                   }
+               }
+           }
+       }
+
+      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), finder, data);
+         replace_typedefs (info, d_right (ret_comp), finder, data);
+         break;
+
+       case DEMANGLE_COMPONENT_NAME:
+         inspect_type (info, ret_comp, finder, data);
+         break;
+
+       case DEMANGLE_COMPONENT_QUAL_NAME:
+         replace_typedefs_qualified_name (info, ret_comp, finder, data);
+         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), finder, data);
+         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), finder, data);
+         break;
+
+       default:
+         break;
+       }
+    }
+}
+
+/* Parse STRING and convert it to canonical form, resolving any
+   typedefs.  If parsing fails, or if STRING is already canonical,
+   return the empty string.  Otherwise return the canonical form.  If
+   FINDER is not NULL, then type components are passed to FINDER to be
+   looked up.  DATA is passed verbatim to FINDER.  */
+
+std::string
+cp_canonicalize_string_full (const char *string,
+                            canonicalization_ftype *finder,
+                            void *data)
+{
+  std::string ret;
+  unsigned int estimated_len;
+  std::unique_ptr<demangle_parse_info> info;
+
+  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.get (), info->tree, finder, data);
+
+      /* Convert the tree back into a string.  */
+      ret = cp_comp_to_string (info->tree, estimated_len);
+      gdb_assert (!ret.empty ());
+
+      /* Finally, compare the original string with the computed
+        name, returning NULL if they are the same.  */
+      if (ret == string)
+       return std::string ();
+    }
+
+  return ret;
+}
+
+/* Like cp_canonicalize_string_full, but always passes NULL for
+   FINDER.  */
+
+std::string
+cp_canonicalize_string_no_typedefs (const char *string)
+{
+  return cp_canonicalize_string_full (string, NULL, NULL);
+}
+
 /* 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.  */
+   or if STRING is already canonical, return the empty string.
+   Otherwise return the canonical form.  */
 
-char *
+std::string
 cp_canonicalize_string (const char *string)
 {
-  struct demangle_component *ret_comp;
+  std::unique_ptr<demangle_parse_info> info;
   unsigned int estimated_len;
-  char *ret;
 
   if (cp_already_canonical (string))
-    return NULL;
+    return std::string ();
 
-  ret_comp = cp_demangled_name_to_comp (string, NULL);
-  if (ret_comp == NULL)
-    return NULL;
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info == NULL)
+    return std::string ();
 
   estimated_len = strlen (string) * 2;
-  ret = cp_comp_to_string (ret_comp, estimated_len);
+  std::string ret = cp_comp_to_string (info->tree, estimated_len);
 
-  if (strcmp (string, ret) == 0)
+  if (ret.empty ())
     {
-      xfree (ret);
-      return NULL;
+      warning (_("internal error: string \"%s\" failed to be canonicalized"),
+              string);
+      return std::string ();
     }
 
+  if (ret == string)
+    return std::string ();
+
   return ret;
 }
 
-/* Convert a mangled name to a demangle_component tree.  *MEMORY is set to the
-   block of used memory that should be freed when finished with the tree. 
-   DEMANGLED_P is set to the char * that should be freed when finished with
-   the tree, or NULL if none was needed.  OPTIONS will be passed to the
-   demangler.  */
+/* Convert a mangled name to a demangle_component tree.  *MEMORY is
+   set to the block of used memory that should be freed when finished
+   with the tree.  DEMANGLED_P is set to the char * that should be
+   freed when finished with the tree, or NULL if none was needed.
+   OPTIONS will be passed to the demangler.  */
 
-static struct demangle_component *
+static std::unique_ptr<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;
-  int len;
 
   /* If it looks like a v3 mangled name, then try to go directly
      to trees.  */
   if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
     {
-      ret = cplus_demangle_v3_components (mangled_name, options, memory);
+      struct demangle_component *ret;
+
+      ret = cplus_demangle_v3_components (mangled_name,
+                                         options, memory);
       if (ret)
        {
+         std::unique_ptr<demangle_parse_info> info (new demangle_parse_info);
+         info->tree = ret;
          *demangled_p = NULL;
-         return ret;
+         return info;
        }
     }
 
-  /* If it doesn't, or if that failed, then try to demangle the name.  */
-  demangled_name = cplus_demangle (mangled_name, options);
+  /* If it doesn't, or if that failed, then try to demangle the
+     name.  */
+  demangled_name = gdb_demangle (mangled_name, options);
   if (demangled_name == NULL)
    return NULL;
   
-  /* If we could demangle the name, parse it to build the component tree.  */
-  ret = cp_demangled_name_to_comp (demangled_name, NULL);
+  /* If we could demangle the name, parse it to build the component
+     tree.  */
+  std::unique_ptr<demangle_parse_info> 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.  */
@@ -198,16 +638,19 @@ 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;
+  std::unique_ptr<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.  */
+  /* First strip off any qualifiers, if we have a function or
+     method.  */
   while (!done)
     switch (ret_comp->type)
       {
@@ -234,9 +677,9 @@ cp_class_name_from_physname (const char *physname)
   if (ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE)
     ret_comp = d_left (ret_comp);
 
-  /* What we have now should be a name, possibly qualified.  Additional
-     qualifiers could live in the left subtree or the right subtree.  Find
-     the last piece.  */
+  /* What we have now should be a name, possibly qualified.
+     Additional qualifiers could live in the left subtree or the right
+     subtree.  Find the last piece.  */
   done = 0;
   prev_comp = NULL;
   cur_comp = ret_comp;
@@ -267,19 +710,20 @@ cp_class_name_from_physname (const char *physname)
     {
       /* We want to discard the rightmost child of PREV_COMP.  */
       *prev_comp = *d_left (prev_comp);
-      /* The ten is completely arbitrary; we don't have a good estimate.  */
+      /* The ten is completely arbitrary; we don't have a good
+        estimate.  */
       ret = cp_comp_to_string (ret_comp, 10);
     }
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
   return ret;
 }
 
-/* Return the child of COMP which is the basename of a method, variable,
-   et cetera.  All scope qualifiers are discarded, but template arguments
-   will be included.  The component tree may be modified.  */
+/* Return the child of COMP which is the basename of a method,
+   variable, et cetera.  All scope qualifiers are discarded, but
+   template arguments will be included.  The component tree may be
+   modified.  */
 
 static struct demangle_component *
 unqualified_name_from_comp (struct demangle_component *comp)
@@ -342,23 +786,23 @@ method_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp;
-  int done;
+  std::unique_ptr<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)
-    /* The ten is completely arbitrary; we don't have a good estimate.  */
+    /* The ten is completely arbitrary; we don't have a good
+       estimate.  */
     ret = cp_comp_to_string (ret_comp, 10);
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
   return ret;
 }
 
@@ -373,13 +817,13 @@ cp_func_name (const char *full_name)
 {
   char *ret;
   struct demangle_component *ret_comp;
-  int done;
+  std::unique_ptr<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)
@@ -397,16 +841,18 @@ cp_remove_params (const char *demangled_name)
 {
   int done = 0;
   struct demangle_component *ret_comp;
+  std::unique_ptr<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)
       {
@@ -549,12 +995,18 @@ cp_find_first_component_aux (const char *name, int permissive)
              return strlen (name);
            }
        case '\0':
-       case ':':
          return index;
+       case ':':
+         /* ':' marks a component iff the next character is also a ':'.
+            Otherwise it is probably malformed input.  */
+         if (name[index + 1] == ':')
+           return index;
+         break;
        case 'o':
          /* Operator names can screw up the recursion.  */
          if (operator_possible
-             && strncmp (name + index, "operator", LENGTH_OF_OPERATOR) == 0)
+             && strncmp (name + index, "operator",
+                         LENGTH_OF_OPERATOR) == 0)
            {
              index += LENGTH_OF_OPERATOR;
              while (ISSPACE(name[index]))
@@ -644,20 +1096,22 @@ cp_entire_prefix_len (const char *name)
 
 /* Test to see if SYM is a symbol that we haven't seen corresponding
    to a function named OLOAD_NAME.  If so, add it to the current
-   completion list. */
+   completion list.  */
 
 static void
-overload_list_add_symbol (struct symbol *sym, const char *oload_name)
+overload_list_add_symbol (struct symbol *sym,
+                         const char *oload_name)
 {
   int newsize;
   int i;
   char *sym_name;
 
-  /* If there is no type information, we can't do anything, so skip */
+  /* If there is no type information, we can't do anything, so
+     skip.  */
   if (SYMBOL_TYPE (sym) == NULL)
     return;
 
-  /* skip any symbols that we've already considered. */
+  /* skip any symbols that we've already considered.  */
   for (i = 0; i < sym_return_val_index; ++i)
     if (strcmp (SYMBOL_LINKAGE_NAME (sym),
                SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0)
@@ -677,12 +1131,13 @@ overload_list_add_symbol (struct symbol *sym, const char *oload_name)
 
   xfree (sym_name);
 
-  /* We have a match for an overload instance, so add SYM to the current list
-   * of overload instances */
+  /* We have a match for an overload instance, so add SYM to the
+     current list of overload instances */
   if (sym_return_val_index + 3 > sym_return_val_size)
     {
       newsize = (sym_return_val_size *= 2) * sizeof (struct symbol *);
-      sym_return_val = (struct symbol **) xrealloc ((char *) sym_return_val, newsize);
+      sym_return_val = (struct symbol **)
+       xrealloc ((char *) sym_return_val, newsize);
     }
   sym_return_val[sym_return_val_index++] = sym;
   sym_return_val[sym_return_val_index] = NULL;
@@ -693,25 +1148,164 @@ overload_list_add_symbol (struct symbol *sym, const char *oload_name)
 
 struct symbol **
 make_symbol_overload_list (const char *func_name,
-                          const char *namespace)
+                          const char *the_namespace)
 {
   struct cleanup *old_cleanups;
+  const char *name;
 
   sym_return_val_size = 100;
   sym_return_val_index = 0;
-  sym_return_val = xmalloc ((sym_return_val_size + 1) *
-                           sizeof (struct symbol *));
+  sym_return_val = XNEWVEC (struct symbol *, sym_return_val_size + 1);
   sym_return_val[0] = NULL;
 
   old_cleanups = make_cleanup (xfree, sym_return_val);
 
-  make_symbol_overload_list_using (func_name, namespace);
+  make_symbol_overload_list_using (func_name, the_namespace);
+
+  if (the_namespace[0] == '\0')
+    name = func_name;
+  else
+    {
+      char *concatenated_name
+       = (char *) alloca (strlen (the_namespace) + 2 + strlen (func_name) + 1);
+      strcpy (concatenated_name, the_namespace);
+      strcat (concatenated_name, "::");
+      strcat (concatenated_name, func_name);
+      name = concatenated_name;
+    }
+
+  make_symbol_overload_list_qualified (name);
 
   discard_cleanups (old_cleanups);
 
   return sym_return_val;
 }
 
+/* Add all symbols with a name matching NAME in BLOCK to the overload
+   list.  */
+
+static void
+make_symbol_overload_list_block (const char *name,
+                                 const struct block *block)
+{
+  struct block_iterator iter;
+  struct symbol *sym;
+
+  ALL_BLOCK_SYMBOLS_WITH_NAME (block, name, iter, sym)
+    overload_list_add_symbol (sym, name);
+}
+
+/* Adds the function FUNC_NAME from NAMESPACE to the overload set.  */
+
+static void
+make_symbol_overload_list_namespace (const char *func_name,
+                                     const char *the_namespace)
+{
+  const char *name;
+  const struct block *block = NULL;
+
+  if (the_namespace[0] == '\0')
+    name = func_name;
+  else
+    {
+      char *concatenated_name
+       = (char *) alloca (strlen (the_namespace) + 2 + strlen (func_name) + 1);
+
+      strcpy (concatenated_name, the_namespace);
+      strcat (concatenated_name, "::");
+      strcat (concatenated_name, func_name);
+      name = concatenated_name;
+    }
+
+  /* Look in the static block.  */
+  block = block_static_block (get_selected_block (0));
+  if (block)
+    make_symbol_overload_list_block (name, block);
+
+  /* Look in the global block.  */
+  block = block_global_block (block);
+  if (block)
+    make_symbol_overload_list_block (name, block);
+
+}
+
+/* Search the namespace of the given type and namespace of and public
+   base types.  */
+
+static void
+make_symbol_overload_list_adl_namespace (struct type *type,
+                                         const char *func_name)
+{
+  char *the_namespace;
+  const char *type_name;
+  int i, prefix_len;
+
+  while (TYPE_CODE (type) == TYPE_CODE_PTR
+        || TYPE_CODE (type) == TYPE_CODE_REF
+         || TYPE_CODE (type) == TYPE_CODE_ARRAY
+         || TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+    {
+      if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+       type = check_typedef(type);
+      else
+       type = TYPE_TARGET_TYPE (type);
+    }
+
+  type_name = TYPE_NAME (type);
+
+  if (type_name == NULL)
+    return;
+
+  prefix_len = cp_entire_prefix_len (type_name);
+
+  if (prefix_len != 0)
+    {
+      the_namespace = (char *) alloca (prefix_len + 1);
+      strncpy (the_namespace, type_name, prefix_len);
+      the_namespace[prefix_len] = '\0';
+
+      make_symbol_overload_list_namespace (func_name, the_namespace);
+    }
+
+  /* Check public base type */
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+      {
+       if (BASETYPE_VIA_PUBLIC (type, i))
+         make_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type,
+                                                                  i),
+                                                  func_name);
+      }
+}
+
+/* Adds the overload list overload candidates for FUNC_NAME found
+   through argument dependent lookup.  */
+
+struct symbol **
+make_symbol_overload_list_adl (struct type **arg_types, int nargs,
+                               const char *func_name)
+{
+  int i;
+
+  gdb_assert (sym_return_val_size != -1);
+
+  for (i = 1; i <= nargs; i++)
+    make_symbol_overload_list_adl_namespace (arg_types[i - 1],
+                                            func_name);
+
+  return sym_return_val;
+}
+
+/* Used for cleanups to reset the "searched" flag in case of an
+   error.  */
+
+static void
+reset_directive_searched (void *data)
+{
+  struct using_direct *direct = (struct using_direct *) data;
+  direct->searched = 0;
+}
+
 /* This applies the using directives to add namespaces to search in,
    and then searches for overloads in all of those namespaces.  It
    adds the symbols found to sym_return_val.  Arguments are as in
@@ -719,40 +1313,50 @@ make_symbol_overload_list (const char *func_name,
 
 static void
 make_symbol_overload_list_using (const char *func_name,
-                                const char *namespace)
+                                const char *the_namespace)
 {
-  const struct using_direct *current;
+  struct using_direct *current;
+  const struct block *block;
 
   /* First, go through the using directives.  If any of them apply,
      look in the appropriate namespaces for new functions to match
      on.  */
 
-  for (current = block_using (get_selected_block (0));
-       current != NULL;
-       current = current->next)
-    {
-      if (strcmp (namespace, current->import_dest) == 0)
-       {
-         make_symbol_overload_list_using (func_name,
-                                          current->import_src);
-       }
-    }
+  for (block = get_selected_block (0);
+       block != NULL;
+       block = BLOCK_SUPERBLOCK (block))
+    for (current = block_using (block);
+       current != NULL;
+       current = current->next)
+      {
+       /* Prevent recursive calls.  */
+       if (current->searched)
+         continue;
+
+        /* If this is a namespace alias or imported declaration ignore
+          it.  */
+        if (current->alias != NULL || current->declaration != NULL)
+          continue;
+
+        if (strcmp (the_namespace, current->import_dest) == 0)
+         {
+           /* Mark this import as searched so that the recursive call
+              does not search it again.  */
+           struct cleanup *old_chain;
+           current->searched = 1;
+           old_chain = make_cleanup (reset_directive_searched,
+                                     current);
+
+           make_symbol_overload_list_using (func_name,
+                                            current->import_src);
+
+           current->searched = 0;
+           discard_cleanups (old_chain);
+         }
+      }
 
   /* Now, add names for this namespace.  */
-  
-  if (namespace[0] == '\0')
-    {
-      make_symbol_overload_list_qualified (func_name);
-    }
-  else
-    {
-      char *concatenated_name
-       = alloca (strlen (namespace) + 2 + strlen (func_name) + 1);
-      strcpy (concatenated_name, namespace);
-      strcat (concatenated_name, "::");
-      strcat (concatenated_name, func_name);
-      make_symbol_overload_list_qualified (concatenated_name);
-    }
+  make_symbol_overload_list_namespace (func_name, the_namespace);
 }
 
 /* This does the bulk of the work of finding overloaded symbols.
@@ -762,93 +1366,49 @@ make_symbol_overload_list_using (const char *func_name,
 static void
 make_symbol_overload_list_qualified (const char *func_name)
 {
-  struct symbol *sym;
-  struct symtab *s;
+  struct compunit_symtab *cust;
   struct objfile *objfile;
   const struct block *b, *surrounding_static_block = 0;
-  struct dict_iterator iter;
-  const struct dictionary *dict;
 
-  /* Look through the partial symtabs for all symbols which begin
-     by matching FUNC_NAME.  Make sure we read that symbol table in. */
+  /* Look through the partial symtabs for all symbols which begin by
+     matching FUNC_NAME.  Make sure we read that symbol table in.  */
 
-  read_in_psymtabs (func_name);
+  ALL_OBJFILES (objfile)
+  {
+    if (objfile->sf)
+      objfile->sf->qf->expand_symtabs_for_function (objfile, func_name);
+  }
 
   /* Search upwards from currently selected frame (so that we can
      complete on local vars.  */
 
   for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
-    {
-      dict = BLOCK_DICT (b);
-
-      for (sym = dict_iter_name_first (dict, func_name, &iter);
-          sym;
-          sym = dict_iter_name_next (func_name, &iter))
-       {
-         overload_list_add_symbol (sym, func_name);
-       }
-    }
+    make_symbol_overload_list_block (func_name, b);
 
   surrounding_static_block = block_static_block (get_selected_block (0));
 
   /* Go through the symtabs and check the externs and statics for
      symbols which match.  */
 
-  ALL_PRIMARY_SYMTABS (objfile, s)
+  ALL_COMPUNITS (objfile, cust)
   {
     QUIT;
-    b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
-    dict = BLOCK_DICT (b);
-
-    for (sym = dict_iter_name_first (dict, func_name, &iter);
-        sym;
-        sym = dict_iter_name_next (func_name, &iter))
-    {
-      overload_list_add_symbol (sym, func_name);
-    }
+    b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
+    make_symbol_overload_list_block (func_name, b);
   }
 
-  ALL_PRIMARY_SYMTABS (objfile, s)
+  ALL_COMPUNITS (objfile, cust)
   {
     QUIT;
-    b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+    b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
     /* Don't do this block twice.  */
     if (b == surrounding_static_block)
       continue;
-    dict = BLOCK_DICT (b);
-
-    for (sym = dict_iter_name_first (dict, func_name, &iter);
-        sym;
-        sym = dict_iter_name_next (func_name, &iter))
-    {
-      overload_list_add_symbol (sym, func_name);
-    }
-  }
-}
-
-/* Look through the partial symtabs for all symbols which begin
-   by matching FUNC_NAME.  Make sure we read that symbol table in. */
-
-static void
-read_in_psymtabs (const char *func_name)
-{
-  struct partial_symtab *ps;
-  struct objfile *objfile;
-
-  ALL_PSYMTABS (objfile, ps)
-  {
-    if (ps->readin)
-      continue;
-
-    if ((lookup_partial_symbol (ps, func_name, NULL, 1, VAR_DOMAIN)
-        != NULL)
-       || (lookup_partial_symbol (ps, func_name, NULL, 0, VAR_DOMAIN)
-           != NULL))
-      psymtab_to_symtab (ps);
+    make_symbol_overload_list_block (func_name, b);
   }
 }
 
-/* Lookup the rtti type for a class name. */
+/* Lookup the rtti type for a class name.  */
 
 struct type *
 cp_lookup_rtti_type (const char *name, struct block *block)
@@ -856,7 +1416,9 @@ cp_lookup_rtti_type (const char *name, struct block *block)
   struct symbol * rtti_sym;
   struct type * rtti_type;
 
-  rtti_sym = lookup_symbol (name, block, STRUCT_DOMAIN, NULL);
+  /* Use VAR_DOMAIN here as NAME may be a typedef.  PR 18141, 18417.
+     Classes "live" in both STRUCT_DOMAIN and VAR_DOMAIN.  */
+  rtti_sym = lookup_symbol (name, block, VAR_DOMAIN, NULL).symbol;
 
   if (rtti_sym == NULL)
     {
@@ -870,11 +1432,11 @@ cp_lookup_rtti_type (const char *name, struct block *block)
       return NULL;
     }
 
-  rtti_type = SYMBOL_TYPE (rtti_sym);
+  rtti_type = check_typedef (SYMBOL_TYPE (rtti_sym));
 
   switch (TYPE_CODE (rtti_type))
     {
-    case TYPE_CODE_CLASS:
+    case TYPE_CODE_STRUCT:
       break;
     case TYPE_CODE_NAMESPACE:
       /* chastain/2003-11-26: the symbol tables often contain fake
@@ -891,13 +1453,157 @@ cp_lookup_rtti_type (const char *name, struct block *block)
   return rtti_type;
 }
 
+#ifdef HAVE_WORKING_FORK
+
+/* If nonzero, attempt to catch crashes in the demangler and print
+   useful debugging information.  */
+
+static int catch_demangler_crashes = 1;
+
+/* Stack context and environment for demangler crash recovery.  */
+
+static SIGJMP_BUF gdb_demangle_jmp_buf;
+
+/* If nonzero, attempt to dump core from the signal handler.  */
+
+static int gdb_demangle_attempt_core_dump = 1;
+
+/* Signal handler for gdb_demangle.  */
+
+static void
+gdb_demangle_signal_handler (int signo)
+{
+  if (gdb_demangle_attempt_core_dump)
+    {
+      if (fork () == 0)
+       dump_core ();
+
+      gdb_demangle_attempt_core_dump = 0;
+    }
+
+  SIGLONGJMP (gdb_demangle_jmp_buf, signo);
+}
+
+#endif
+
+/* A wrapper for bfd_demangle.  */
+
+char *
+gdb_demangle (const char *name, int options)
+{
+  char *result = NULL;
+  int crash_signal = 0;
+
+#ifdef HAVE_WORKING_FORK
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+  struct sigaction sa, old_sa;
+#else
+  sighandler_t ofunc;
+#endif
+  static int core_dump_allowed = -1;
+
+  if (core_dump_allowed == -1)
+    {
+      core_dump_allowed = can_dump_core (LIMIT_CUR);
+
+      if (!core_dump_allowed)
+       gdb_demangle_attempt_core_dump = 0;
+    }
+
+  if (catch_demangler_crashes)
+    {
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+      sa.sa_handler = gdb_demangle_signal_handler;
+      sigemptyset (&sa.sa_mask);
+#ifdef HAVE_SIGALTSTACK
+      sa.sa_flags = SA_ONSTACK;
+#else
+      sa.sa_flags = 0;
+#endif
+      sigaction (SIGSEGV, &sa, &old_sa);
+#else
+      ofunc = signal (SIGSEGV, gdb_demangle_signal_handler);
+#endif
+
+      crash_signal = SIGSETJMP (gdb_demangle_jmp_buf);
+    }
+#endif
+
+  if (crash_signal == 0)
+    result = bfd_demangle (NULL, name, options);
+
+#ifdef HAVE_WORKING_FORK
+  if (catch_demangler_crashes)
+    {
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+      sigaction (SIGSEGV, &old_sa, NULL);
+#else
+      signal (SIGSEGV, ofunc);
+#endif
+
+      if (crash_signal != 0)
+       {
+         static int error_reported = 0;
+
+         if (!error_reported)
+           {
+             char *short_msg, *long_msg;
+             struct cleanup *back_to;
+
+             short_msg = xstrprintf (_("unable to demangle '%s' "
+                                     "(demangler failed with signal %d)"),
+                                   name, crash_signal);
+             back_to = make_cleanup (xfree, short_msg);
+
+             long_msg = xstrprintf ("%s:%d: %s: %s", __FILE__, __LINE__,
+                                   "demangler-warning", short_msg);
+             make_cleanup (xfree, long_msg);
+
+             make_cleanup_restore_target_terminal ();
+             target_terminal_ours_for_output ();
+
+             begin_line ();
+             if (core_dump_allowed)
+               fprintf_unfiltered (gdb_stderr,
+                                   _("%s\nAttempting to dump core.\n"),
+                                   long_msg);
+             else
+               warn_cant_dump_core (long_msg);
+
+             demangler_warning (__FILE__, __LINE__, "%s", short_msg);
+
+             do_cleanups (back_to);
+
+             error_reported = 1;
+           }
+
+         result = NULL;
+       }
+    }
+#endif
+
+  return result;
+}
+
+/* See cp-support.h.  */
+
+int
+gdb_sniff_from_mangled_name (const char *mangled, char **demangled)
+{
+  *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+  return *demangled != NULL;
+}
+
 /* Don't allow just "maintenance cplus".  */
 
 static  void
 maint_cplus_command (char *arg, int from_tty)
 {
-  printf_unfiltered (_("\"maintenance cplus\" must be followed by the name of a command.\n"));
-  help_list (maint_cplus_cmd_list, "maintenance cplus ", -1, gdb_stdout);
+  printf_unfiltered (_("\"maintenance cplus\" must be followed "
+                      "by the name of a command.\n"));
+  help_list (maint_cplus_cmd_list,
+            "maintenance cplus ",
+            all_commands, gdb_stdout);
 }
 
 /* This is a front end for cp_find_first_component, for unit testing.
@@ -914,7 +1620,7 @@ first_component_command (char *arg, int from_tty)
     return;
 
   len = cp_find_first_component (arg);
-  prefix = alloca (len + 1);
+  prefix = (char *) alloca (len + 1);
 
   memcpy (prefix, arg, len);
   prefix[len] = '\0';
@@ -924,116 +1630,53 @@ first_component_command (char *arg, int from_tty)
 
 extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */
 
-#define SKIP_SPACE(P)                          \
-  do                                           \
-  {                                            \
-    while (*(P) == ' ' || *(P) == '\t')                \
-      ++(P);                                   \
-  }                                            \
-  while (0)
-
-/* Returns the length of the operator name or 0 if INPUT does not
-   point to a valid C++ operator.  INPUT should start with "operator".  */
-int
-cp_validate_operator (const char *input)
-{
-  int i;
-  char *copy;
-  const char *p;
-  struct expression *expr;
-  struct value *val;
-  struct gdb_exception except;
-  struct cleanup *old_chain;
-
-  p = input;
-
-  if (strncmp (p, "operator", 8) == 0)
-    {
-      int valid = 0;
-      p += 8;
-
-      SKIP_SPACE (p);
-      for (i = 0; i < sizeof (operator_tokens) / sizeof (operator_tokens[0]);
-          ++i)
-       {
-         int length = strlen (operator_tokens[i]);
-         /* By using strncmp here, we MUST have operator_tokens ordered!
-            See additional notes where operator_tokens is defined above.  */
-         if (strncmp (p, operator_tokens[i], length) == 0)
-           {
-             const char *op = p;
-             valid = 1;
-             p += length;
-
-             if (strncmp (op, "new", 3) == 0
-                 || strncmp (op, "delete", 6) == 0)
-               {
 
-                 /* Special case: new[] and delete[].  We must be careful
-                    to swallow whitespace before/in "[]".  */
-                 SKIP_SPACE (p);
+/* Implement "info vtbl".  */
 
-                 if (*p == '[')
-                   {
-                     ++p;
-                     SKIP_SPACE (p);
-                     if (*p == ']')
-                       ++p;
-                     else
-                       valid = 0;
-                   }
-               }
-
-             if (valid)
-               return (p - input);
-           }
-       }
-
-      /* Check input for a conversion operator.  */
-
-      /* Skip past base typename */
-      while (*p != '*' && *p != '&' && *p != 0 && *p != ' ')
-       ++p;
-      SKIP_SPACE (p);
-
-      /* Add modifiers '*'/'&' */
-      while (*p == '*' || *p == '&')
-       {
-         ++p;
-         SKIP_SPACE (p);
-       }
-
-      /* Check for valid type.  [Remember: input starts with 
-        "operator".]  */
-      copy = savestring (input + 8, p - input - 8);
-      expr = NULL;
-      val = NULL;
-      TRY_CATCH (except, RETURN_MASK_ALL)
-       {
-         expr = parse_expression (copy);
-         val = evaluate_type (expr);
-       }
-
-      xfree (copy);
-      if (expr)
-       xfree (expr);
-
-      if (val != NULL && value_type (val) != NULL)
-       return (p - input);
-    }
+static void
+info_vtbl_command (char *arg, int from_tty)
+{
+  struct value *value;
 
-  return 0;
+  value = parse_and_eval (arg);
+  cplus_print_vtable (value);
 }
 
 void
 _initialize_cp_support (void)
 {
-  add_prefix_cmd ("cplus", class_maintenance, maint_cplus_command,
-                 _("C++ maintenance commands."), &maint_cplus_cmd_list,
-                 "maintenance cplus ", 0, &maintenancelist);
-  add_alias_cmd ("cp", "cplus", class_maintenance, 1, &maintenancelist);
-
-  add_cmd ("first_component", class_maintenance, first_component_command,
+  add_prefix_cmd ("cplus", class_maintenance,
+                 maint_cplus_command,
+                 _("C++ maintenance commands."),
+                 &maint_cplus_cmd_list,
+                 "maintenance cplus ",
+                 0, &maintenancelist);
+  add_alias_cmd ("cp", "cplus",
+                class_maintenance, 1,
+                &maintenancelist);
+
+  add_cmd ("first_component",
+          class_maintenance,
+          first_component_command,
           _("Print the first class/namespace component of NAME."),
           &maint_cplus_cmd_list);
+
+  add_info ("vtbl", info_vtbl_command,
+           _("Show the virtual function table for a C++ object.\n\
+Usage: info vtbl EXPRESSION\n\
+Evaluate EXPRESSION and display the virtual function table for the\n\
+resulting object."));
+
+#ifdef HAVE_WORKING_FORK
+  add_setshow_boolean_cmd ("catch-demangler-crashes", class_maintenance,
+                          &catch_demangler_crashes, _("\
+Set whether to attempt to catch demangler crashes."), _("\
+Show whether to attempt to catch demangler crashes."), _("\
+If enabled GDB will attempt to catch demangler crashes and\n\
+display the offending symbol."),
+                          NULL,
+                          NULL,
+                          &maintenance_set_cmdlist,
+                          &maintenance_show_cmdlist);
+#endif
 }
This page took 0.060239 seconds and 4 git commands to generate.