return mtype;
}
+/* See gdbtypes.h. */
+
+bool
+operator== (const dynamic_prop &l, const dynamic_prop &r)
+{
+ if (l.kind != r.kind)
+ return false;
+
+ switch (l.kind)
+ {
+ case PROP_UNDEFINED:
+ return true;
+ case PROP_CONST:
+ return l.data.const_val == r.data.const_val;
+ case PROP_ADDR_OFFSET:
+ case PROP_LOCEXPR:
+ case PROP_LOCLIST:
+ return l.data.baton == r.data.baton;
+ }
+
+ gdb_assert_not_reached ("unhandled dynamic_prop kind");
+}
+
+/* See gdbtypes.h. */
+
+bool
+operator== (const range_bounds &l, const range_bounds &r)
+{
+#define FIELD_EQ(FIELD) (l.FIELD == r.FIELD)
+
+ return (FIELD_EQ (low)
+ && FIELD_EQ (high)
+ && FIELD_EQ (flag_upper_bound_is_count)
+ && FIELD_EQ (flag_bound_evaluated));
+
+#undef FIELD_EQ
+}
+
/* Create a range type with a dynamic range from LOW_BOUND to
HIGH_BOUND, inclusive. See create_range_type for further details. */
*highp = -*lowp - 1;
return 0;
}
- /* ... fall through for unsigned ints ... */
+ /* fall through */
case TYPE_CODE_CHAR:
*lowp = 0;
/* This round-about calculation is to avoid shifting by
Elements will be of type ELEMENT_TYPE, the indices will be of type
RANGE_TYPE.
+ BYTE_STRIDE_PROP, when not NULL, provides the array's byte stride.
+ This byte stride property is added to the resulting array type
+ as a DYN_PROP_BYTE_STRIDE. As a consequence, the BYTE_STRIDE_PROP
+ argument can only be used to create types that are objfile-owned
+ (see add_dyn_prop), meaning that either this function must be called
+ with an objfile-owned RESULT_TYPE, or an objfile-owned RANGE_TYPE.
+
+ BIT_STRIDE is taken into account only when BYTE_STRIDE_PROP is NULL.
If BIT_STRIDE is not zero, build a packed array type whose element
size is BIT_STRIDE. Otherwise, ignore this parameter.
create_array_type_with_stride (struct type *result_type,
struct type *element_type,
struct type *range_type,
+ struct dynamic_prop *byte_stride_prop,
unsigned int bit_stride)
{
+ if (byte_stride_prop != NULL
+ && byte_stride_prop->kind == PROP_CONST)
+ {
+ /* The byte stride is actually not dynamic. Pretend we were
+ called with bit_stride set instead of byte_stride_prop.
+ This will give us the same result type, while avoiding
+ the need to handle this as a special case. */
+ bit_stride = byte_stride_prop->data.const_val * 8;
+ byte_stride_prop = NULL;
+ }
+
if (result_type == NULL)
result_type = alloc_type_copy (range_type);
TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
TYPE_TARGET_TYPE (result_type) = element_type;
- if (has_static_range (TYPE_RANGE_DATA (range_type))
+ if (byte_stride_prop == NULL
+ && has_static_range (TYPE_RANGE_DATA (range_type))
&& (!type_not_associated (result_type)
&& !type_not_allocated (result_type)))
{
TYPE_FIELDS (result_type) =
(struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
TYPE_INDEX_TYPE (result_type) = range_type;
- if (bit_stride > 0)
+ if (byte_stride_prop != NULL)
+ add_dyn_prop (DYN_PROP_BYTE_STRIDE, *byte_stride_prop, result_type);
+ else if (bit_stride > 0)
TYPE_FIELD_BITSIZE (result_type, 0) = bit_stride;
/* TYPE_TARGET_STUB will take care of zero length arrays. */
struct type *range_type)
{
return create_array_type_with_stride (result_type, element_type,
- range_type, 0);
+ range_type, NULL, 0);
}
struct type *
lookup_array_range_type (struct type *element_type,
LONGEST low_bound, LONGEST high_bound)
{
- struct gdbarch *gdbarch = get_type_arch (element_type);
- struct type *index_type = builtin_type (gdbarch)->builtin_int;
- struct type *range_type
- = create_static_range_type (NULL, index_type, low_bound, high_bound);
+ struct type *index_type;
+ struct type *range_type;
+
+ if (TYPE_OBJFILE_OWNED (element_type))
+ index_type = objfile_type (TYPE_OWNER (element_type).objfile)->builtin_int;
+ else
+ index_type = builtin_type (get_type_arch (element_type))->builtin_int;
+ range_type = create_static_range_type (NULL, index_type,
+ low_bound, high_bound);
return create_array_type (NULL, element_type, range_type);
}
static void
stub_noname_complaint (void)
{
- complaint (&symfile_complaints, _("stub type has NULL name"));
+ complaint (_("stub type has NULL name"));
+}
+
+/* Return nonzero if TYPE has a DYN_PROP_BYTE_STRIDE dynamic property
+ attached to it, and that property has a non-constant value. */
+
+static int
+array_type_has_dynamic_stride (struct type *type)
+{
+ struct dynamic_prop *prop = get_dyn_prop (DYN_PROP_BYTE_STRIDE, type);
+
+ return (prop != NULL && prop->kind != PROP_CONST);
}
/* Worker for is_dynamic_type. */
{
gdb_assert (TYPE_NFIELDS (type) == 1);
- /* The array is dynamic if either the bounds are dynamic,
- or the elements it contains have a dynamic contents. */
+ /* The array is dynamic if either the bounds are dynamic... */
if (is_dynamic_type_internal (TYPE_INDEX_TYPE (type), 0))
return 1;
- return is_dynamic_type_internal (TYPE_TARGET_TYPE (type), 0);
+ /* ... or the elements it contains have a dynamic contents... */
+ if (is_dynamic_type_internal (TYPE_TARGET_TYPE (type), 0))
+ return 1;
+ /* ... or if it has a dynamic stride... */
+ if (array_type_has_dynamic_stride (type))
+ return 1;
+ return 0;
}
case TYPE_CODE_STRUCT:
struct type *range_type;
struct type *ary_dim;
struct dynamic_prop *prop;
+ unsigned int bit_stride = 0;
gdb_assert (TYPE_CODE (type) == TYPE_CODE_ARRAY);
else
elt_type = TYPE_TARGET_TYPE (type);
- return create_array_type_with_stride (type, elt_type, range_type,
- TYPE_FIELD_BITSIZE (type, 0));
+ prop = get_dyn_prop (DYN_PROP_BYTE_STRIDE, type);
+ if (prop != NULL)
+ {
+ int prop_eval_ok
+ = dwarf2_evaluate_property (prop, NULL, addr_stack, &value);
+
+ if (prop_eval_ok)
+ {
+ remove_dyn_prop (DYN_PROP_BYTE_STRIDE, type);
+ bit_stride = (unsigned int) (value * 8);
+ }
+ else
+ {
+ /* Could be a bug in our code, but it could also happen
+ if the DWARF info is not correct. Issue a warning,
+ and assume no byte/bit stride (leave bit_stride = 0). */
+ warning (_("cannot determine array stride for type %s"),
+ TYPE_NAME (type) ? TYPE_NAME (type) : "<no name>");
+ }
+ }
+ else
+ bit_stride = TYPE_FIELD_BITSIZE (type, 0);
+
+ return create_array_type_with_stride (type, elt_type, range_type, NULL,
+ bit_stride);
}
/* Resolve dynamic bounds of members of the union TYPE to static
void
add_dyn_prop (enum dynamic_prop_node_kind prop_kind, struct dynamic_prop prop,
- struct type *type, struct objfile *objfile)
+ struct type *type)
{
struct dynamic_prop_list *temp;
gdb_assert (TYPE_OBJFILE_OWNED (type));
- temp = XOBNEW (&objfile->objfile_obstack, struct dynamic_prop_list);
+ temp = XOBNEW (&TYPE_OBJFILE (type)->objfile_obstack,
+ struct dynamic_prop_list);
temp->prop_kind = prop_kind;
temp->prop = prop;
temp->next = TYPE_DYN_PROP_LIST (type);
return t;
}
+/* See gdbtypes.h. */
+
+unsigned
+type_raw_align (struct type *type)
+{
+ if (type->align_log2 != 0)
+ return 1 << (type->align_log2 - 1);
+ return 0;
+}
+
+/* See gdbtypes.h. */
+
+unsigned
+type_align (struct type *type)
+{
+ unsigned raw_align = type_raw_align (type);
+ if (raw_align != 0)
+ return raw_align;
+
+ ULONGEST align = 0;
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_FLAGS:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_DECFLOAT:
+ {
+ struct gdbarch *arch = get_type_arch (type);
+ align = gdbarch_type_align (arch, type);
+ }
+ break;
+
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_COMPLEX:
+ case TYPE_CODE_TYPEDEF:
+ align = type_align (TYPE_TARGET_TYPE (type));
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ {
+ if (TYPE_NFIELDS (type) == 0)
+ {
+ /* An empty struct has alignment 1. */
+ align = 1;
+ break;
+ }
+ for (unsigned i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ ULONGEST f_align = type_align (TYPE_FIELD_TYPE (type, i));
+ if (f_align == 0)
+ {
+ /* Don't pretend we know something we don't. */
+ align = 0;
+ break;
+ }
+ if (f_align > align)
+ align = f_align;
+ }
+ }
+ break;
+
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ /* Not sure what to do here, and these can't appear in C or C++
+ anyway. */
+ break;
+
+ case TYPE_CODE_METHODPTR:
+ case TYPE_CODE_MEMBERPTR:
+ align = TYPE_LENGTH (type);
+ break;
+
+ case TYPE_CODE_VOID:
+ align = 1;
+ break;
+
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_METHOD:
+ default:
+ break;
+ }
+
+ if ((align & (align - 1)) != 0)
+ {
+ /* Not a power of 2, so pass. */
+ align = 0;
+ }
+
+ return align;
+}
+
+/* See gdbtypes.h. */
+
+bool
+set_type_align (struct type *type, ULONGEST align)
+{
+ /* Must be a power of 2. Zero is ok. */
+ gdb_assert ((align & (align - 1)) == 0);
+
+ unsigned result = 0;
+ while (align != 0)
+ {
+ ++result;
+ align >>= 1;
+ }
+
+ if (result >= (1 << TYPE_ALIGN_BITS))
+ return false;
+
+ type->align_log2 = result;
+ return true;
+}
+
\f
/* Queries on types. */
return 1;
}
-/* Compares type A to type B returns 1 if the represent the same type
- 0 otherwise. */
+/* Compares type A to type B. Returns true if they represent the same
+ type, false otherwise. */
-int
+bool
types_equal (struct type *a, struct type *b)
{
/* Identical type pointers. */
and a. The reason is that builtin types are different from
the same ones constructed from the object. */
if (a == b)
- return 1;
+ return true;
/* Resolve typedefs */
if (TYPE_CODE (a) == TYPE_CODE_TYPEDEF)
/* If after resolving typedefs a and b are not of the same type
code then they are not equal. */
if (TYPE_CODE (a) != TYPE_CODE (b))
- return 0;
+ return false;
/* If a and b are both pointers types or both reference types then
they are equal of the same type iff the objects they refer to are
if (TYPE_NAME (a) && TYPE_NAME (b)
&& strcmp (TYPE_NAME (a), TYPE_NAME (b)) == 0)
- return 1;
+ return true;
/* Check if identical after resolving typedefs. */
if (a == b)
- return 1;
+ return true;
/* Two function types are equal if their argument and return types
are equal. */
int i;
if (TYPE_NFIELDS (a) != TYPE_NFIELDS (b))
- return 0;
+ return false;
if (!types_equal (TYPE_TARGET_TYPE (a), TYPE_TARGET_TYPE (b)))
- return 0;
+ return false;
for (i = 0; i < TYPE_NFIELDS (a); ++i)
if (!types_equal (TYPE_FIELD_TYPE (a, i), TYPE_FIELD_TYPE (b, i)))
- return 0;
+ return false;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
\f
/* Deep comparison of types. */
/* An entry in the type-equality bcache. */
-typedef struct type_equality_entry
+struct type_equality_entry
{
- struct type *type1, *type2;
-} type_equality_entry_d;
+ type_equality_entry (struct type *t1, struct type *t2)
+ : type1 (t1),
+ type2 (t2)
+ {
+ }
-DEF_VEC_O (type_equality_entry_d);
+ struct type *type1, *type2;
+};
-/* A helper function to compare two strings. Returns 1 if they are
- the same, 0 otherwise. Handles NULLs properly. */
+/* A helper function to compare two strings. Returns true if they are
+ the same, false otherwise. Handles NULLs properly. */
-static int
+static bool
compare_maybe_null_strings (const char *s, const char *t)
{
- if (s == NULL && t != NULL)
- return 0;
- else if (s != NULL && t == NULL)
- return 0;
- else if (s == NULL && t== NULL)
- return 1;
+ if (s == NULL || t == NULL)
+ return s == t;
return strcmp (s, t) == 0;
}
/* A helper function for check_types_worklist that checks two types for
- "deep" equality. Returns non-zero if the types are considered the
- same, zero otherwise. */
+ "deep" equality. Returns true if the types are considered the
+ same, false otherwise. */
-static int
+static bool
check_types_equal (struct type *type1, struct type *type2,
- VEC (type_equality_entry_d) **worklist)
+ std::vector<type_equality_entry> *worklist)
{
type1 = check_typedef (type1);
type2 = check_typedef (type2);
if (type1 == type2)
- return 1;
+ return true;
if (TYPE_CODE (type1) != TYPE_CODE (type2)
|| TYPE_LENGTH (type1) != TYPE_LENGTH (type2)
|| TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
|| TYPE_INSTANCE_FLAGS (type1) != TYPE_INSTANCE_FLAGS (type2)
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
- return 0;
+ return false;
if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
TYPE_TAG_NAME (type2)))
- return 0;
+ return false;
if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
- return 0;
+ return false;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
{
- if (memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2),
- sizeof (*TYPE_RANGE_DATA (type1))) != 0)
- return 0;
+ if (*TYPE_RANGE_DATA (type1) != *TYPE_RANGE_DATA (type2))
+ return false;
}
else
{
{
const struct field *field1 = &TYPE_FIELD (type1, i);
const struct field *field2 = &TYPE_FIELD (type2, i);
- struct type_equality_entry entry;
if (FIELD_ARTIFICIAL (*field1) != FIELD_ARTIFICIAL (*field2)
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
- return 0;
+ return false;
if (!compare_maybe_null_strings (FIELD_NAME (*field1),
FIELD_NAME (*field2)))
- return 0;
+ return false;
switch (FIELD_LOC_KIND (*field1))
{
case FIELD_LOC_KIND_BITPOS:
if (FIELD_BITPOS (*field1) != FIELD_BITPOS (*field2))
- return 0;
+ return false;
break;
case FIELD_LOC_KIND_ENUMVAL:
if (FIELD_ENUMVAL (*field1) != FIELD_ENUMVAL (*field2))
- return 0;
+ return false;
break;
case FIELD_LOC_KIND_PHYSADDR:
if (FIELD_STATIC_PHYSADDR (*field1)
!= FIELD_STATIC_PHYSADDR (*field2))
- return 0;
+ return false;
break;
case FIELD_LOC_KIND_PHYSNAME:
if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
FIELD_STATIC_PHYSNAME (*field2)))
- return 0;
+ return false;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
{
if (block1->per_cu != block2->per_cu
|| block1->size != block2->size
|| memcmp (block1->data, block2->data, block1->size) != 0)
- return 0;
+ return false;
}
break;
default:
FIELD_LOC_KIND (*field1));
}
- entry.type1 = FIELD_TYPE (*field1);
- entry.type2 = FIELD_TYPE (*field2);
- VEC_safe_push (type_equality_entry_d, *worklist, &entry);
+ worklist->emplace_back (FIELD_TYPE (*field1), FIELD_TYPE (*field2));
}
}
if (TYPE_TARGET_TYPE (type1) != NULL)
{
- struct type_equality_entry entry;
-
if (TYPE_TARGET_TYPE (type2) == NULL)
- return 0;
+ return false;
- entry.type1 = TYPE_TARGET_TYPE (type1);
- entry.type2 = TYPE_TARGET_TYPE (type2);
- VEC_safe_push (type_equality_entry_d, *worklist, &entry);
+ worklist->emplace_back (TYPE_TARGET_TYPE (type1),
+ TYPE_TARGET_TYPE (type2));
}
else if (TYPE_TARGET_TYPE (type2) != NULL)
- return 0;
+ return false;
- return 1;
+ return true;
}
-/* Check types on a worklist for equality. Returns zero if any pair
- is not equal, non-zero if they are all considered equal. */
+/* Check types on a worklist for equality. Returns false if any pair
+ is not equal, true if they are all considered equal. */
-static int
-check_types_worklist (VEC (type_equality_entry_d) **worklist,
+static bool
+check_types_worklist (std::vector<type_equality_entry> *worklist,
struct bcache *cache)
{
- while (!VEC_empty (type_equality_entry_d, *worklist))
+ while (!worklist->empty ())
{
- struct type_equality_entry entry;
int added;
- entry = *VEC_last (type_equality_entry_d, *worklist);
- VEC_pop (type_equality_entry_d, *worklist);
+ struct type_equality_entry entry = std::move (worklist->back ());
+ worklist->pop_back ();
/* If the type pair has already been visited, we know it is
ok. */
if (!added)
continue;
- if (check_types_equal (entry.type1, entry.type2, worklist) == 0)
- return 0;
+ if (!check_types_equal (entry.type1, entry.type2, worklist))
+ return false;
}
- return 1;
+ return true;
}
-/* Return non-zero if types TYPE1 and TYPE2 are equal, as determined by a
- "deep comparison". Otherwise return zero. */
+/* Return true if types TYPE1 and TYPE2 are equal, as determined by a
+ "deep comparison". Otherwise return false. */
-int
+bool
types_deeply_equal (struct type *type1, struct type *type2)
{
struct gdb_exception except = exception_none;
- int result = 0;
+ bool result = false;
struct bcache *cache;
- VEC (type_equality_entry_d) *worklist = NULL;
- struct type_equality_entry entry;
+ std::vector<type_equality_entry> worklist;
gdb_assert (type1 != NULL && type2 != NULL);
/* Early exit for the simple case. */
if (type1 == type2)
- return 1;
+ return true;
cache = bcache_xmalloc (NULL, NULL);
- entry.type1 = type1;
- entry.type2 = type2;
- VEC_safe_push (type_equality_entry_d, worklist, &entry);
+ worklist.emplace_back (type1, type2);
/* check_types_worklist calls several nested helper functions, some
of which can raise a GDB exception, so we just check and rethrow
END_CATCH
bcache_xfree (cache);
- VEC_free (type_equality_entry_d, worklist);
/* Rethrow if there was a problem. */
if (except.reason < 0)
return INTEGER_CONVERSION_BADNESS;
else if (TYPE_LENGTH (arg) < TYPE_LENGTH (parm))
return INTEGER_PROMOTION_BADNESS;
- /* >>> !! else fall through !! <<< */
+ /* fall through */
case TYPE_CODE_CHAR:
/* Deal with signed, unsigned, and plain chars for C++ and
with int cases falling through from previous case. */
rank.subrank = distance_to_ancestor (parm, arg, 0);
if (rank.subrank >= 0)
return sum_ranks (BASE_CONVERSION_BADNESS, rank);
- /* else fall through */
+ /* fall through */
default:
return INCOMPATIBLE_TYPE_BADNESS;
}
/* Trivial helpers for the libiberty hash table, for mapping one
type to another. */
-struct type_pair
+struct type_pair : public allocate_on_obstack
{
- struct type *old, *newobj;
+ type_pair (struct type *old_, struct type *newobj_)
+ : old (old_), newobj (newobj_)
+ {}
+
+ struct type * const old, * const newobj;
};
static hashval_t
struct type *type,
htab_t copied_types)
{
- struct type_pair *stored, pair;
void **slot;
struct type *new_type;
if it did, the type might disappear unexpectedly. */
gdb_assert (TYPE_OBJFILE (type) == objfile);
- pair.old = type;
+ struct type_pair pair (type, nullptr);
+
slot = htab_find_slot (copied_types, &pair, INSERT);
if (*slot != NULL)
return ((struct type_pair *) *slot)->newobj;
/* We must add the new type to the hash table immediately, in case
we encounter this type again during a recursive call below. */
- stored = XOBNEW (&objfile->objfile_obstack, struct type_pair);
- stored->old = type;
- stored->newobj = new_type;
+ struct type_pair *stored
+ = new (&objfile->objfile_obstack) struct type_pair (type, new_type);
+
*slot = stored;
/* Copy the common fields of types. For the main type, we simply
objfile_type->nodebug_text_gnu_ifunc_symbol
= init_type (objfile, TYPE_CODE_FUNC, TARGET_CHAR_BIT,
"<text gnu-indirect-function variable, no debug info>");
- /* Ifunc resolvers return a function address. */
- TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
- = init_integer_type (objfile, gdbarch_addr_bit (gdbarch), 1,
- "__IFUNC_RESOLVER_RET");
TYPE_GNU_IFUNC (objfile_type->nodebug_text_gnu_ifunc_symbol) = 1;
objfile_type->nodebug_got_plt_symbol
= init_pointer_type (objfile, gdbarch_addr_bit (gdbarch),