]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Convert typedef hash to new hash table
authorSimon Marchi <simon.marchi@efficios.com>
Mon, 4 Nov 2024 18:27:50 +0000 (13:27 -0500)
committerSimon Marchi <simon.marchi@polymtl.ca>
Tue, 26 Nov 2024 03:07:04 +0000 (22:07 -0500)
This converts the typedef hash to use the new hash table.

This patch found a latent bug in the typedef code.  Previously, the
hash function looked at the type name, but the hash equality function
used types_equal -- but that strips typedefs, meaning that equality of
types did not imply equality of hashes.  This patch fixes the problem
and updates the relevant test.

Change-Id: I0d10236b01e74bac79621244a1c0c56f90d65594
Co-Authored-By: Tom Tromey <tom@tromey.com>
Approved-By: Tom Tromey <tom@tromey.com>
gdb/testsuite/gdb.cp/ptype-flags.exp
gdb/typeprint.c
gdb/typeprint.h

index bb92da6122ae0f16237dc0762812f58534ff3851..476c075f2872128e3978547d5a2ee231ec22e7de 100644 (file)
@@ -78,10 +78,18 @@ proc do_check_holder {name {flags ""} {show_typedefs 1} {show_methods 1}
 proc do_check_typedef_holder {name {flags ""} {show_typedefs 1} {show_methods 1}
                              {raw 0}} {
 
-    set contents {
-       { field public "double a;" }
-       { field public "ns::scoped_double b;" }
-       { field public "global_double c;" }
+    if {$raw} {
+       set contents {
+           { field public "double a;" }
+           { field public "ns::scoped_double b;" }
+           { field public "global_double c;" }
+       }
+    } else {
+       set contents {
+           { field public "class_double a;" }
+           { field public "class_double b;" }
+           { field public "class_double c;" }
+       }
     }
 
     if {$show_typedefs} {
@@ -89,8 +97,13 @@ proc do_check_typedef_holder {name {flags ""} {show_typedefs 1} {show_methods 1}
     }
 
     if {$show_methods} {
-       lappend contents { method private "double method1(ns::scoped_double);" }
-       lappend contents { method private "double method2(global_double);" }
+       if {$raw} {
+           lappend contents { method private "double method1(ns::scoped_double);" }
+           lappend contents { method private "double method2(global_double);" }
+       } else {
+           lappend contents { method private "class_double method1(class_double);" }
+           lappend contents { method private "class_double method2(class_double);" }
+       }
     }
 
     if {$raw} {
index 1b9e18f1001cc2cdc3d1c410c0f876e845a39915..6494103ba93f08c0cf5b61fefbf87a37cd56230f 100644 (file)
@@ -194,49 +194,16 @@ print_offset_data::finish (struct type *type, int level,
 
 \f
 
-/* A hash function for a typedef_field.  */
-
-static hashval_t
-hash_typedef_field (const void *p)
-{
-  const struct decl_field *tf = (const struct decl_field *) p;
-
-  return htab_hash_string (TYPE_SAFE_NAME (tf->type));
-}
-
-/* An equality function for a typedef field.  */
-
-static int
-eq_typedef_field (const void *a, const void *b)
-{
-  const struct decl_field *tfa = (const struct decl_field *) a;
-  const struct decl_field *tfb = (const struct decl_field *) b;
-
-  return types_equal (tfa->type, tfb->type);
-}
-
 /* See typeprint.h.  */
 
 void
 typedef_hash_table::recursively_update (struct type *t)
 {
-  int i;
-
-  for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
-    {
-      struct decl_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
-      void **slot;
-
-      slot = htab_find_slot (m_table.get (), tdef, INSERT);
-      /* Only add a given typedef name once.  Really this shouldn't
-        happen; but it is safe enough to do the updates breadth-first
-        and thus use the most specific typedef.  */
-      if (*slot == NULL)
-       *slot = tdef;
-    }
+  for (int i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
+    m_table.emplace (&TYPE_TYPEDEF_FIELD (t, i));
 
   /* Recurse into superclasses.  */
-  for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
+  for (int i = 0; i < TYPE_N_BASECLASSES (t); ++i)
     recursively_update (TYPE_BASECLASS (t, i));
 }
 
@@ -250,7 +217,6 @@ typedef_hash_table::add_template_parameters (struct type *t)
   for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
     {
       struct decl_field *tf;
-      void **slot;
 
       /* We only want type-valued template parameters in the hash.  */
       if (TYPE_TEMPLATE_ARGUMENT (t, i)->aclass () != LOC_TYPEDEF)
@@ -260,45 +226,10 @@ typedef_hash_table::add_template_parameters (struct type *t)
       tf->name = TYPE_TEMPLATE_ARGUMENT (t, i)->linkage_name ();
       tf->type = TYPE_TEMPLATE_ARGUMENT (t, i)->type ();
 
-      slot = htab_find_slot (m_table.get (), tf, INSERT);
-      if (*slot == NULL)
-       *slot = tf;
+      m_table.emplace (tf);
     }
 }
 
-/* See typeprint.h.  */
-
-typedef_hash_table::typedef_hash_table ()
-  : m_table (htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
-                               NULL, xcalloc, xfree))
-{
-}
-
-/* Helper function for typedef_hash_table::copy.  */
-
-static int
-copy_typedef_hash_element (void **slot, void *nt)
-{
-  htab_t new_table = (htab_t) nt;
-  void **new_slot;
-
-  new_slot = htab_find_slot (new_table, *slot, INSERT);
-  if (*new_slot == NULL)
-    *new_slot = *slot;
-
-  return 1;
-}
-
-/* See typeprint.h.  */
-
-typedef_hash_table::typedef_hash_table (const typedef_hash_table &table)
-{
-  m_table.reset (htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
-                                   NULL, xcalloc, xfree));
-  htab_traverse_noresize (table.m_table.get (), copy_typedef_hash_element,
-                         m_table.get ());
-}
-
 /* Look up the type T in the global typedef hash.  If it is found,
    return the typedef name.  If it is not found, apply the
    type-printers, if any, given by start_script_type_printers and return the
@@ -308,29 +239,21 @@ const char *
 typedef_hash_table::find_global_typedef (const struct type_print_options *flags,
                                         struct type *t)
 {
-  void **slot;
-  struct decl_field tf, *new_tf;
-
   if (flags->global_typedefs == NULL)
     return NULL;
 
-  tf.name = NULL;
-  tf.type = t;
-
-  slot = htab_find_slot (flags->global_typedefs->m_table.get (), &tf, INSERT);
-  if (*slot != NULL)
-    {
-      new_tf = (struct decl_field *) *slot;
-      return new_tf->name;
-    }
+  if (auto it = flags->global_typedefs->m_table.find (t);
+      it != flags->global_typedefs->m_table.end ())
+    return (*it)->name;
 
   /* Put an entry into the hash table now, in case
      apply_ext_lang_type_printers recurses.  */
-  new_tf = XOBNEW (&flags->global_typedefs->m_storage, struct decl_field);
+  decl_field *new_tf
+    = XOBNEW (&flags->global_typedefs->m_storage, struct decl_field);
   new_tf->name = NULL;
   new_tf->type = t;
 
-  *slot = new_tf;
+  flags->global_typedefs->m_table.emplace (new_tf);
 
   gdb::unique_xmalloc_ptr<char> applied
     = apply_ext_lang_type_printers (flags->global_printers, t);
@@ -350,15 +273,9 @@ typedef_hash_table::find_typedef (const struct type_print_options *flags,
 {
   if (flags->local_typedefs != NULL)
     {
-      struct decl_field tf, *found;
-
-      tf.name = NULL;
-      tf.type = t;
-      htab_t table = flags->local_typedefs->m_table.get ();
-      found = (struct decl_field *) htab_find (table, &tf);
-
-      if (found != NULL)
-       return found->name;
+      if (auto iter = flags->local_typedefs->m_table.find (t);
+         iter != flags->local_typedefs->m_table.end ())
+       return (*iter)->name;
     }
 
   return find_global_typedef (flags, t);
index fe43fc148f49999653ae0574361edd90ee4994d1..3cba02f7172c0e85792535baa620557490debec1 100644 (file)
 #ifndef TYPEPRINT_H
 #define TYPEPRINT_H
 
-#include "gdbsupport/gdb-hashtab.h"
 #include "gdbsupport/gdb_obstack.h"
+#include "gdbsupport/unordered_set.h"
+#include "gdbtypes.h"
+#include "hashtab.h"
 
 enum language;
 struct ui_file;
@@ -115,19 +117,21 @@ private:
 
 extern const struct type_print_options type_print_raw_options;
 
-/* A hash table holding typedef_field objects.  This is more
-   complicated than an ordinary hash because it must also track the
-   lifetime of some -- but not all -- of the contained objects.  */
+/* A hash table holding decl_field objects.  This is more complicated than an
+   ordinary hash because it must also track the lifetime of some -- but not all
+   -- of the contained objects.  */
 
 class typedef_hash_table
 {
 public:
 
   /* Create a new typedef-lookup hash table.  */
-  typedef_hash_table ();
+  typedef_hash_table () = default;
 
   /* Copy a typedef hash.  */
-  typedef_hash_table (const typedef_hash_table &);
+  typedef_hash_table (const typedef_hash_table &other)
+    : m_table (other.m_table)
+  {}
 
   typedef_hash_table &operator= (const typedef_hash_table &) = delete;
 
@@ -150,9 +154,36 @@ private:
   static const char *find_global_typedef (const struct type_print_options *flags,
                                          struct type *t);
 
+  struct decl_field_type_hash
+  {
+    using is_transparent = void;
 
-  /* The actual hash table.  */
-  htab_up m_table;
+    std::size_t operator() (type *t) const noexcept
+    {
+      /* Use check_typedef: the hash must agree with equals, and types_equal
+        strips typedefs.  */
+      return htab_hash_string (TYPE_SAFE_NAME (check_typedef (t)));
+    }
+
+    std::size_t operator() (const decl_field *f) const noexcept
+    { return (*this) (f->type); }
+  };
+
+  struct decl_field_type_eq
+  {
+    using is_transparent = void;
+
+    bool operator () (type *t, const decl_field *f) const noexcept
+    { return types_equal (t, f->type); }
+
+    bool operator() (const decl_field *lhs,
+                    const decl_field *rhs) const noexcept
+    { return (*this) (lhs->type, rhs); }
+  };
+
+  /* The actual hash table of `decl_field *` identified by their type field.  */
+  gdb::unordered_set<decl_field *, decl_field_type_hash, decl_field_type_eq>
+    m_table;
 
   /* Storage for typedef_field objects that must be synthesized.  */
   auto_obstack m_storage;