Initial support for variant parts

This adds some initial support for variant parts to gdbtypes.h.  A
variant part is represented as a union.  The union has a flag
indicating that it has a discriminant, and information about the
discriminant is attached using the dynamic property system.

2018-02-26  Tom Tromey  <tom@tromey.com>

	* value.h (value_union_variant): Declare.
	* valops.c (value_union_variant): New function.
	* gdbtypes.h (TYPE_FLAG_DISCRIMINATED_UNION): New macro.
	(struct discriminant_info): New.
	(enum dynamic_prop_node_kind) <DYN_PROP_DISCRIMINATED>: New
	enumerator.
	(struct main_type) <flag_discriminated_union>: New field.
This commit is contained in:
Tom Tromey
2018-02-09 13:31:42 -07:00
parent 15ce8941e7
commit 7c22600aab
4 changed files with 113 additions and 0 deletions

View File

@@ -1,3 +1,13 @@
2018-02-26 Tom Tromey <tom@tromey.com>
* value.h (value_union_variant): Declare.
* valops.c (value_union_variant): New function.
* gdbtypes.h (TYPE_FLAG_DISCRIMINATED_UNION): New macro.
(struct discriminant_info): New.
(enum dynamic_prop_node_kind) <DYN_PROP_DISCRIMINATED>: New
enumerator.
(struct main_type) <flag_discriminated_union>: New field.
2018-02-26 Tom Tromey <tom@tromey.com>
* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add

View File

@@ -312,6 +312,14 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
#define TYPE_FLAG_ENUM(t) (TYPE_MAIN_TYPE (t)->flag_flag_enum)
/* * True if this type is a discriminated union type. Only valid for
TYPE_CODE_UNION. A discriminated union stores a reference to the
discriminant field along with the discriminator values in a dynamic
property. */
#define TYPE_FLAG_DISCRIMINATED_UNION(t) \
(TYPE_MAIN_TYPE (t)->flag_discriminated_union)
/* * Constant type. If this is set, the corresponding type has a
const modifier. */
@@ -381,6 +389,39 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
#define TYPE_ADDRESS_CLASS_ALL(t) (TYPE_INSTANCE_FLAGS(t) \
& TYPE_INSTANCE_FLAG_ADDRESS_CLASS_ALL)
/* * Information needed for a discriminated union. A discriminated
union is handled somewhat differently from an ordinary union.
One field is designated as the discriminant. Only one other field
is active at a time; which one depends on the value of the
discriminant and the data in this structure.
Additionally, it is possible to have a univariant discriminated
union. In this case, the union has just a single field, which is
assumed to be the only active variant -- in this case no
discriminant is provided. */
struct discriminant_info
{
/* * The index of the discriminant field. If -1, then this union
must have just a single field. */
int discriminant_index;
/* * The index of the default branch of the union. If -1, then
there is no default branch. */
int default_index;
/* * The discriminant values corresponding to each branch. This has
a number of entries equal to the number of fields in this union.
If discriminant_index is not -1, then that entry in this array is
not used. If default_index is not -1, then that entry in this
array is not used. */
ULONGEST discriminants[1];
};
enum dynamic_prop_kind
{
PROP_UNDEFINED, /* Not defined. */
@@ -439,6 +480,9 @@ enum dynamic_prop_node_kind
/* A property providing an array's byte stride. */
DYN_PROP_BYTE_STRIDE,
/* A property holding information about a discriminated union. */
DYN_PROP_DISCRIMINATED,
};
/* * List for dynamic type attributes. */
@@ -658,6 +702,13 @@ struct main_type
unsigned int flag_flag_enum : 1;
/* * True if this type is a discriminated union type. Only valid
for TYPE_CODE_UNION. A discriminated union stores a reference to
the discriminant field along with the discriminator values in a
dynamic property. */
unsigned int flag_discriminated_union : 1;
/* * A discriminant telling us which field of the type_specific
union is being used for this type, if any. */

View File

@@ -2257,6 +2257,50 @@ value_struct_elt_bitpos (struct value **argp, int bitpos, struct type *ftype,
return NULL;
}
/* See value.h. */
int
value_union_variant (struct type *union_type, const gdb_byte *contents)
{
gdb_assert (TYPE_CODE (union_type) == TYPE_CODE_UNION
&& TYPE_FLAG_DISCRIMINATED_UNION (union_type));
struct dynamic_prop *discriminant_prop
= get_dyn_prop (DYN_PROP_DISCRIMINATED, union_type);
gdb_assert (discriminant_prop != nullptr);
struct discriminant_info *info
= (struct discriminant_info *) discriminant_prop->data.baton;
gdb_assert (info != nullptr);
/* If this is a univariant union, just return the sole field. */
if (TYPE_NFIELDS (union_type) == 1)
return 0;
/* This should only happen for univariants, which we already dealt
with. */
gdb_assert (info->discriminant_index != -1);
/* Compute the discriminant. Note that unpack_field_as_long handles
sign extension when necessary, as does the DWARF reader -- so
signed discriminants will be handled correctly despite the use of
an unsigned type here. */
ULONGEST discriminant = unpack_field_as_long (union_type, contents,
info->discriminant_index);
for (int i = 0; i < TYPE_NFIELDS (union_type); ++i)
{
if (i != info->default_index
&& i != info->discriminant_index
&& discriminant == info->discriminants[i])
return i;
}
if (info->default_index == -1)
error (_("Could not find variant corresponding to discriminant %s"),
pulongest (discriminant));
return info->default_index;
}
/* Search through the methods of an object (and its bases) to find a
specified method. Return the pointer to the fn_field list FN_LIST of
overloaded instances defined in the source language. If available

View File

@@ -1169,4 +1169,12 @@ extern struct type *result_type_of_xmethod (struct value *method,
extern struct value *call_xmethod (struct value *method,
int argc, struct value **argv);
/* Given a discriminated union type and some corresponding value
contents, this will return the field index of the currently active
variant. This will throw an exception if no active variant can be
found. */
extern int value_union_variant (struct type *union_type,
const gdb_byte *contents);
#endif /* !defined (VALUE_H) */