[gdb/build] Use move capture in gdb_demangle
[binutils-gdb.git] / gdb / cp-support.c
index eba477d549d1c124338fb2d67551c79322388d91..0300727434d93471ccc389b039331178eab8e307 100644 (file)
@@ -1,5 +1,5 @@
 /* Helper routines for C++ support in GDB.
-   Copyright (C) 2002-2021 Free Software Foundation, Inc.
+   Copyright (C) 2002-2023 Free Software Foundation, Inc.
 
    Contributed by MontaVista Software.
 
@@ -20,6 +20,7 @@
 
 #include "defs.h"
 #include "cp-support.h"
+#include "language.h"
 #include "demangle.h"
 #include "gdbcmd.h"
 #include "dictionary.h"
 #include "namespace.h"
 #include <signal.h>
 #include "gdbsupport/gdb_setjmp.h"
-#include "safe-ctype.h"
+#include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/selftest.h"
 #include "gdbsupport/gdb-sigmask.h"
 #include <atomic>
 #include "event-top.h"
 #include "run-on-main-thread.h"
+#include "typeprint.h"
 
 #define d_left(dc) (dc)->u.s_binary.left
 #define d_right(dc) (dc)->u.s_binary.right
@@ -70,18 +72,16 @@ static void add_symbol_overload_list_qualified
 
 struct cmd_list_element *maint_cplus_cmd_list = NULL;
 
-/* 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,
                    canonicalization_ftype *finder,
                    void *data);
 
+static struct demangle_component *
+  gdb_cplus_demangle_v3_components (const char *mangled,
+                                   int options, void **mem);
+
 /* 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.
 
@@ -146,13 +146,6 @@ inspect_type (struct demangle_parse_info *info,
   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 (int i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
-    {
-      if (strcmp (name, ignore_typedefs[i]) == 0)
-       return 0;
-    }
-
   sym = NULL;
 
   try
@@ -166,7 +159,7 @@ inspect_type (struct demangle_parse_info *info,
 
   if (sym != NULL)
     {
-      struct type *otype = SYMBOL_TYPE (sym);
+      struct type *otype = sym->type ();
 
       if (finder != NULL)
        {
@@ -220,10 +213,10 @@ inspect_type (struct demangle_parse_info *info,
              struct type *last = otype;
 
              /* Find the last typedef for the type.  */
-             while (TYPE_TARGET_TYPE (last) != NULL
-                    && (TYPE_TARGET_TYPE (last)->code ()
+             while (last->target_type () != NULL
+                    && (last->target_type ()->code ()
                         == TYPE_CODE_TYPEDEF))
-               last = TYPE_TARGET_TYPE (last);
+               last = last->target_type ();
 
              /* If there is only one typedef for this anonymous type,
                 do not substitute it.  */
@@ -238,7 +231,14 @@ inspect_type (struct demangle_parse_info *info,
          string_file buf;
          try
            {
-             type_print (type, "", &buf, -1);
+             /* Avoid using the current language.  If the language is
+                C, and TYPE is a struct/class, the printed type is
+                prefixed with "struct " or "class ", which we don't
+                want when we're expanding a C++ typedef.  Print using
+                the type symbol's language to expand a C++ typedef
+                the C++ way even if the current language is C.  */
+             const language_defn *lang = language_def (sym->language ());
+             lang->print_type (type, "", &buf, -1, 0, &type_print_raw_options);
            }
          /* If type_print threw an exception, there is little point
             in continuing, so just bow out gracefully.  */
@@ -512,7 +512,7 @@ replace_typedefs (struct demangle_parse_info *info,
 
              if (sym != NULL)
                {
-                 struct type *otype = SYMBOL_TYPE (sym);
+                 struct type *otype = sym->type ();
                  const char *new_name = (*finder) (otype, data);
 
                  if (new_name != NULL)
@@ -661,18 +661,17 @@ cp_canonicalize_string (const char *string)
 
 static std::unique_ptr<demangle_parse_info>
 mangled_name_to_comp (const char *mangled_name, int options,
-                     void **memory, char **demangled_p)
+                     void **memory,
+                     gdb::unique_xmalloc_ptr<char> *demangled_p)
 {
-  char *demangled_name;
-
   /* 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);
+      ret = gdb_cplus_demangle_v3_components (mangled_name,
+                                             options, memory);
       if (ret)
        {
          std::unique_ptr<demangle_parse_info> info (new demangle_parse_info);
@@ -684,22 +683,20 @@ mangled_name_to_comp (const char *mangled_name, int options,
 
   /* If it doesn't, or if that failed, then try to demangle the
      name.  */
-  demangled_name = gdb_demangle (mangled_name, options);
+  gdb::unique_xmalloc_ptr<char> 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.  */
   std::unique_ptr<demangle_parse_info> info
-    = cp_demangled_name_to_comp (demangled_name, NULL);
+    = cp_demangled_name_to_comp (demangled_name.get (), NULL);
 
   if (info == NULL)
-    {
-      xfree (demangled_name);
-      return NULL;
-    }
+    return NULL;
 
-  *demangled_p = demangled_name;
+  *demangled_p = std::move (demangled_name);
   return info;
 }
 
@@ -709,7 +706,7 @@ char *
 cp_class_name_from_physname (const char *physname)
 {
   void *storage = NULL;
-  char *demangled_name = NULL;
+  gdb::unique_xmalloc_ptr<char> demangled_name;
   gdb::unique_xmalloc_ptr<char> ret;
   struct demangle_component *ret_comp, *prev_comp, *cur_comp;
   std::unique_ptr<demangle_parse_info> info;
@@ -789,7 +786,6 @@ cp_class_name_from_physname (const char *physname)
     }
 
   xfree (storage);
-  xfree (demangled_name);
   return ret.release ();
 }
 
@@ -857,7 +853,7 @@ char *
 method_name_from_physname (const char *physname)
 {
   void *storage = NULL;
-  char *demangled_name = NULL;
+  gdb::unique_xmalloc_ptr<char> demangled_name;
   gdb::unique_xmalloc_ptr<char> ret;
   struct demangle_component *ret_comp;
   std::unique_ptr<demangle_parse_info> info;
@@ -875,7 +871,6 @@ method_name_from_physname (const char *physname)
     ret = cp_comp_to_string (ret_comp, 10);
 
   xfree (storage);
-  xfree (demangled_name);
   return ret.release ();
 }
 
@@ -1220,7 +1215,7 @@ overload_list_add_symbol (struct symbol *sym,
 {
   /* If there is no type information, we can't do anything, so
      skip.  */
-  if (SYMBOL_TYPE (sym) == NULL)
+  if (sym->type () == NULL)
     return;
 
   /* skip any symbols that we've already considered.  */
@@ -1279,12 +1274,9 @@ add_symbol_overload_list_block (const char *name,
                                const struct block *block,
                                std::vector<symbol *> *overload_list)
 {
-  struct block_iterator iter;
-  struct symbol *sym;
-
   lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
 
-  ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
+  for (struct symbol *sym : block_iterator_range (block, &lookup_name))
     overload_list_add_symbol (sym, name, overload_list);
 }
 
@@ -1312,15 +1304,17 @@ add_symbol_overload_list_namespace (const char *func_name,
     }
 
   /* Look in the static block.  */
-  block = block_static_block (get_selected_block (0));
-  if (block)
-    add_symbol_overload_list_block (name, block, overload_list);
-
-  /* Look in the global block.  */
-  block = block_global_block (block);
-  if (block)
-    add_symbol_overload_list_block (name, block, overload_list);
+  block = get_selected_block (0);
+  block = block == nullptr ? nullptr : block->static_block ();
+  if (block != nullptr)
+    {
+      add_symbol_overload_list_block (name, block, overload_list);
 
+      /* Look in the global block.  */
+      block = block->global_block ();
+      if (block)
+       add_symbol_overload_list_block (name, block, overload_list);
+    }
 }
 
 /* Search the namespace of the given type and namespace of and public
@@ -1335,15 +1329,14 @@ add_symbol_overload_list_adl_namespace (struct type *type,
   const char *type_name;
   int i, prefix_len;
 
-  while (type->code () == TYPE_CODE_PTR
-        || TYPE_IS_REFERENCE (type)
+  while (type->is_pointer_or_reference ()
         || type->code () == TYPE_CODE_ARRAY
         || type->code () == TYPE_CODE_TYPEDEF)
     {
       if (type->code () == TYPE_CODE_TYPEDEF)
        type = check_typedef (type);
       else
-       type = TYPE_TARGET_TYPE (type);
+       type = type->target_type ();
     }
 
   type_name = type->name ();
@@ -1406,8 +1399,8 @@ add_symbol_overload_list_using (const char *func_name,
 
   for (block = get_selected_block (0);
        block != NULL;
-       block = BLOCK_SUPERBLOCK (block))
-    for (current = block_using (block);
+       block = block->superblock ())
+    for (current = block->get_using ();
        current != NULL;
        current = current->next)
       {
@@ -1446,7 +1439,7 @@ static void
 add_symbol_overload_list_qualified (const char *func_name,
                                    std::vector<symbol *> *overload_list)
 {
-  const struct block *b, *surrounding_static_block = 0;
+  const struct block *surrounding_static_block = 0;
 
   /* Look through the partial symtabs for all symbols which begin by
      matching FUNC_NAME.  Make sure we read that symbol table in.  */
@@ -1457,36 +1450,43 @@ add_symbol_overload_list_qualified (const char *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))
+  for (const block *b = get_selected_block (0);
+       b != nullptr;
+       b = b->superblock ())
     add_symbol_overload_list_block (func_name, b, overload_list);
 
-  surrounding_static_block = block_static_block (get_selected_block (0));
+  surrounding_static_block = get_selected_block (0);
+  surrounding_static_block = (surrounding_static_block == nullptr
+                             ? nullptr
+                             : surrounding_static_block->static_block ());
 
   /* Go through the symtabs and check the externs and statics for
      symbols which match.  */
 
-  for (objfile *objfile : current_program_space->objfiles ())
-    {
-      for (compunit_symtab *cust : objfile->compunits ())
-       {
-         QUIT;
-         b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
-         add_symbol_overload_list_block (func_name, b, overload_list);
-       }
-    }
-
-  for (objfile *objfile : current_program_space->objfiles ())
-    {
-      for (compunit_symtab *cust : objfile->compunits ())
-       {
-         QUIT;
-         b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
-         /* Don't do this block twice.  */
-         if (b == surrounding_static_block)
-           continue;
-         add_symbol_overload_list_block (func_name, b, overload_list);
-       }
-    }
+  const block *block = get_selected_block (0);
+  struct objfile *current_objfile = block ? block->objfile () : nullptr;
+
+  gdbarch_iterate_over_objfiles_in_search_order
+    (current_objfile ? current_objfile->arch () : target_gdbarch (),
+     [func_name, surrounding_static_block, &overload_list]
+     (struct objfile *obj)
+       {
+        for (compunit_symtab *cust : obj->compunits ())
+          {
+            QUIT;
+            const struct block *b = cust->blockvector ()->global_block ();
+            add_symbol_overload_list_block (func_name, b, overload_list);
+
+            b = cust->blockvector ()->static_block ();
+            /* Don't do this block twice.  */
+            if (b == surrounding_static_block)
+              continue;
+
+            add_symbol_overload_list_block (func_name, b, overload_list);
+          }
+
+        return 0;
+       }, current_objfile);
 }
 
 /* Lookup the rtti type for a class name.  */
@@ -1507,13 +1507,13 @@ cp_lookup_rtti_type (const char *name, const struct block *block)
       return NULL;
     }
 
-  if (SYMBOL_CLASS (rtti_sym) != LOC_TYPEDEF)
+  if (rtti_sym->aclass () != LOC_TYPEDEF)
     {
       warning (_("RTTI symbol for class '%s' is not a type"), name);
       return NULL;
     }
 
-  rtti_type = check_typedef (SYMBOL_TYPE (rtti_sym));
+  rtti_type = check_typedef (rtti_sym->type ());
 
   switch (rtti_type->code ())
     {
@@ -1589,9 +1589,9 @@ report_failed_demangle (const char *name, bool core_dump_allowed,
 
       begin_line ();
       if (core_dump_allowed)
-       fprintf_unfiltered (gdb_stderr,
-                           _("%s\nAttempting to dump core.\n"),
-                           long_msg.c_str ());
+       gdb_printf (gdb_stderr,
+                   _("%s\nAttempting to dump core.\n"),
+                   long_msg.c_str ());
       else
        warn_cant_dump_core (long_msg.c_str ());
 
@@ -1605,10 +1605,10 @@ report_failed_demangle (const char *name, bool core_dump_allowed,
 
 /* A wrapper for bfd_demangle.  */
 
-char *
+gdb::unique_xmalloc_ptr<char>
 gdb_demangle (const char *name, int options)
 {
-  char *result = NULL;
+  gdb::unique_xmalloc_ptr<char> result;
   int crash_signal = 0;
 
 #ifdef HAVE_WORKING_FORK
@@ -1637,7 +1637,7 @@ gdb_demangle (const char *name, int options)
 #endif
 
   if (crash_signal == 0)
-    result = bfd_demangle (NULL, name, options);
+    result.reset (bfd_demangle (NULL, name, options | DMGL_VERBOSE));
 
 #ifdef HAVE_WORKING_FORK
   if (catch_demangler_crashes)
@@ -1656,7 +1656,13 @@ gdb_demangle (const char *name, int options)
             we might be in a background thread.  Instead, arrange for
             the reporting to happen on the main thread.  */
          std::string copy = name;
-         run_on_main_thread ([=] ()
+         run_on_main_thread ([
+#if __cplusplus >= 201402L
+                              =, copy = std::move (copy)
+#else
+                              =
+#endif
+                              ] ()
            {
              report_failed_demangle (copy.c_str (), core_dump_allowed,
                                      crash_signal);
@@ -1672,6 +1678,28 @@ gdb_demangle (const char *name, int options)
 
 /* See cp-support.h.  */
 
+char *
+gdb_cplus_demangle_print (int options,
+                         struct demangle_component *tree,
+                         int estimated_length,
+                         size_t *p_allocated_size)
+{
+  return cplus_demangle_print (options | DMGL_VERBOSE, tree,
+                              estimated_length, p_allocated_size);
+}
+
+/* A wrapper for cplus_demangle_v3_components that forces
+   DMGL_VERBOSE.  */
+
+static struct demangle_component *
+gdb_cplus_demangle_v3_components (const char *mangled,
+                                 int options, void **mem)
+{
+  return cplus_demangle_v3_components (mangled, options | DMGL_VERBOSE, mem);
+}
+
+/* See cp-support.h.  */
+
 unsigned int
 cp_search_name_hash (const char *search_name)
 {
@@ -1698,6 +1726,12 @@ cp_search_name_hash (const char *search_name)
          && string[5] != ':')
        break;
 
+      /* Ignore template parameter lists.  */
+      if (string[0] == '<'
+         && string[1] != '(' && string[1] != '<' && string[1] != '='
+         && string[1] != ' ' && string[1] != '\0')
+       break;
+
       hash = SYMBOL_HASH_NEXT (hash, *string);
     }
   return hash;
@@ -1748,10 +1782,12 @@ cp_symbol_name_matches_1 (const char *symbol_search_name,
   completion_match_for_lcd *match_for_lcd
     = (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
 
+  gdb_assert (match_for_lcd == nullptr || match_for_lcd->empty ());
+
   while (true)
     {
       if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
-                               mode, language_cplus, match_for_lcd) == 0)
+                               mode, language_cplus, match_for_lcd, true) == 0)
        {
          if (comp_match_res != NULL)
            {
@@ -1781,6 +1817,11 @@ cp_symbol_name_matches_1 (const char *symbol_search_name,
          return true;
        }
 
+      /* Clear match_for_lcd so the next strncmp_iw_with_mode call starts
+        from scratch.  */
+      if (match_for_lcd != nullptr)
+       match_for_lcd->clear ();
+
       unsigned int len = cp_find_first_component (sname);
 
       if (sname[len] == '\0')
@@ -2068,7 +2109,7 @@ quote (const char *str)
 /* Check that removing parameter info out of NAME produces EXPECTED.
    COMPLETION_MODE indicates whether we're testing normal and
    completion mode.  FILE and LINE are used to provide better test
-   location information in case ithe check fails.  */
+   location information in case the check fails.  */
 
 static void
 check_remove_params (const char *file, int line,
@@ -2191,7 +2232,7 @@ first_component_command (const char *arg, int from_tty)
   memcpy (prefix, arg, len);
   prefix[len] = '\0';
 
-  printf_unfiltered ("%s\n", prefix);
+  gdb_printf ("%s\n", prefix);
 }
 
 /* Implement "info vtbl".  */
@@ -2205,17 +2246,90 @@ info_vtbl_command (const char *arg, int from_tty)
   cplus_print_vtable (value);
 }
 
+/* See description in cp-support.h.  */
+
+const char *
+find_toplevel_char (const char *s, char c)
+{
+  int quoted = 0;              /* zero if we're not in quotes;
+                                  '"' if we're in a double-quoted string;
+                                  '\'' if we're in a single-quoted string.  */
+  int depth = 0;               /* Number of unclosed parens we've seen.  */
+  const char *scan;
+
+  for (scan = s; *scan; scan++)
+    {
+      if (quoted)
+       {
+         if (*scan == quoted)
+           quoted = 0;
+         else if (*scan == '\\' && *(scan + 1))
+           scan++;
+       }
+      else if (*scan == c && ! quoted && depth == 0)
+       return scan;
+      else if (*scan == '"' || *scan == '\'')
+       quoted = *scan;
+      else if (*scan == '(' || *scan == '<')
+       depth++;
+      else if ((*scan == ')' || *scan == '>') && depth > 0)
+       depth--;
+      else if (*scan == 'o' && !quoted && depth == 0)
+       {
+         /* Handle C++ operator names.  */
+         if (strncmp (scan, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0)
+           {
+             scan += CP_OPERATOR_LEN;
+             if (*scan == c)
+               return scan;
+             while (ISSPACE (*scan))
+               {
+                 ++scan;
+                 if (*scan == c)
+                   return scan;
+               }
+             if (*scan == '\0')
+               break;
+
+             switch (*scan)
+               {
+                 /* Skip over one less than the appropriate number of
+                    characters: the for loop will skip over the last
+                    one.  */
+               case '<':
+                 if (scan[1] == '<')
+                   {
+                     scan++;
+                     if (*scan == c)
+                       return scan;
+                   }
+                 break;
+               case '>':
+                 if (scan[1] == '>')
+                   {
+                     scan++;
+                     if (*scan == c)
+                       return scan;
+                   }
+                 break;
+               }
+           }
+       }
+    }
+
+  return 0;
+}
+
 void _initialize_cp_support ();
 void
 _initialize_cp_support ()
 {
-  add_basic_prefix_cmd ("cplus", class_maintenance,
-                       _("C++ maintenance commands."),
-                       &maint_cplus_cmd_list,
-                       "maintenance cplus ",
-                       0, &maintenancelist);
-  add_alias_cmd ("cp", "cplus",
-                class_maintenance, 1,
+  cmd_list_element *maintenance_cplus
+    = add_basic_prefix_cmd ("cplus", class_maintenance,
+                           _("C++ maintenance commands."),
+                           &maint_cplus_cmd_list,
+                           0, &maintenancelist);
+  add_alias_cmd ("cp", maintenance_cplus, class_maintenance, 1,
                 &maintenancelist);
 
   add_cmd ("first_component",