forked from Imagelibrary/binutils-gdb
Convert typedef hash to new hash table
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>
This commit is contained in:
committed by
Simon Marchi
parent
cd1a05c76f
commit
56246f3099
@@ -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} {
|
||||
|
||||
109
gdb/typeprint.c
109
gdb/typeprint.c
@@ -194,49 +194,16 @@ print_offset_data::finish (struct type *type, int level,
|
||||
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
#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;
|
||||
|
||||
Reference in New Issue
Block a user