summaryrefslogtreecommitdiff
path: root/gdb/gdbtypes.h
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2020-04-24 13:40:31 -0600
committerTom Tromey <tromey@adacore.com>2020-04-24 13:40:31 -0600
commitef83a141a291474f1364d6c64ee7a207b96b8e19 (patch)
treeff9631e4ec9fa56f4bd480982b6ed04af5816b8a /gdb/gdbtypes.h
parent675127ec647e08ceabc66ec7d3ad560d91deacad (diff)
downloadbinutils-gdb-ef83a141a291474f1364d6c64ee7a207b96b8e19.tar.gz
Add new variant part code
This patch adds the infrastructure for the new variant part code. At this point, nothing uses this code. This is done in a separate patch to make it simpler to review. I examined a few possible approaches to handling variant parts. In particular, I considered having a DWARF variant part be a union (similar to how the Rust code works now); and I considered having type fields have a flag indicating that they are variants. Having separate types seemed bad conceptually, because these variants aren't truly separate -- they rely on the "parent" type. And, changing how fields worked seemed excessively invasive. So, in the end I thought the approach taken in this patch was both simple to implement and understand, without losing generality. The idea in this patch is that all the fields of a type with variant parts will be stored in a single field array, just as if they'd all been listed directly. Then, the variants are attached as a dynamic property. These control which fields end up in the type that's constructed during dynamic type resolution. gdb/ChangeLog 2020-04-24 Tom Tromey <tromey@adacore.com> * gdbtypes.c (is_dynamic_type_internal): Check for variant parts. (variant::matches, compute_variant_fields_recurse) (compute_variant_fields_inner, compute_variant_fields): New functions. (resolve_dynamic_struct): Check for DYN_PROP_VARIANT_PARTS. Use resolved_type after type is made. (operator==): Add new cases. * gdbtypes.h (TYPE_HAS_VARIANT_PARTS): New macro. (struct discriminant_range, struct variant, struct variant_part): New. (union dynamic_prop_data) <variant_parts, original_type>: New members. (enum dynamic_prop_node_kind) <DYN_PROP_VARIANT_PARTS>: New constant. (enum dynamic_prop_kind) <PROP_TYPE, PROP_VARIANT_PARTS>: New constants. * value.c (unpack_bits_as_long): Now public. * value.h (unpack_bits_as_long): Declare.
Diffstat (limited to 'gdb/gdbtypes.h')
-rw-r--r--gdb/gdbtypes.h105
1 files changed, 104 insertions, 1 deletions
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 77cc92e419d..8b4da6e3f9f 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -51,6 +51,7 @@
#include "gdbsupport/underlying.h"
#include "gdbsupport/print-utils.h"
#include "dwarf2.h"
+#include "gdb_obstack.h"
/* Forward declarations for prototypes. */
struct field;
@@ -358,6 +359,10 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
#define TYPE_IS_ALLOCATABLE(t) \
(get_dyn_prop (DYN_PROP_ALLOCATED, t) != NULL)
+/* * True if this type has variant parts. */
+#define TYPE_HAS_VARIANT_PARTS(t) \
+ (get_dyn_prop (DYN_PROP_VARIANT_PARTS, t) != nullptr)
+
/* * Instruction-space delimited type. This is for Harvard architectures
which have separate instruction and data address spaces (and perhaps
others).
@@ -399,6 +404,84 @@ 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 about a single discriminant. */
+
+struct discriminant_range
+{
+ /* * The range of values for the variant. This is an inclusive
+ range. */
+ ULONGEST low, high;
+
+ /* * Return true if VALUE is contained in this range. IS_UNSIGNED
+ is true if this should be an unsigned comparison; false for
+ signed. */
+ bool contains (ULONGEST value, bool is_unsigned) const
+ {
+ if (is_unsigned)
+ return value >= low && value <= high;
+ LONGEST valuel = (LONGEST) value;
+ return valuel >= (LONGEST) low && valuel <= (LONGEST) high;
+ }
+};
+
+struct variant_part;
+
+/* * A single variant. A variant has a list of discriminant values.
+ When the discriminator matches one of these, the variant is
+ enabled. Each variant controls zero or more fields; and may also
+ control other variant parts as well. This struct corresponds to
+ DW_TAG_variant in DWARF. */
+
+struct variant : allocate_on_obstack
+{
+ /* * The discriminant ranges for this variant. */
+ gdb::array_view<discriminant_range> discriminants;
+
+ /* * The fields controlled by this variant. This is inclusive on
+ the low end and exclusive on the high end. A variant may not
+ control any fields, in which case the two values will be equal.
+ These are indexes into the type's array of fields. */
+ int first_field;
+ int last_field;
+
+ /* * Variant parts controlled by this variant. */
+ gdb::array_view<variant_part> parts;
+
+ /* * Return true if this is the default variant. The default
+ variant can be recognized because it has no associated
+ discriminants. */
+ bool is_default () const
+ {
+ return discriminants.empty ();
+ }
+
+ /* * Return true if this variant matches VALUE. IS_UNSIGNED is true
+ if this should be an unsigned comparison; false for signed. */
+ bool matches (ULONGEST value, bool is_unsigned) const;
+};
+
+/* * A variant part. Each variant part has an optional discriminant
+ and holds an array of variants. This struct corresponds to
+ DW_TAG_variant_part in DWARF. */
+
+struct variant_part : allocate_on_obstack
+{
+ /* * The index of the discriminant field in the outer type. This is
+ an index into the type's array of fields. If this is -1, there
+ is no discriminant, and only the default variant can be
+ considered to be selected. */
+ int discriminant_index;
+
+ /* * True if this discriminant is unsigned; false if signed. This
+ comes from the type of the discriminant. */
+ bool is_unsigned;
+
+ /* * The variants that are controlled by this variant part. Note
+ that these will always be sorted by field number. */
+ gdb::array_view<variant> variants;
+};
+
+
/* * Information needed for a discriminated union. A discriminated
union is handled somewhat differently from an ordinary union.
@@ -438,7 +521,9 @@ enum dynamic_prop_kind
PROP_CONST, /* Constant. */
PROP_ADDR_OFFSET, /* Address offset. */
PROP_LOCEXPR, /* Location expression. */
- PROP_LOCLIST /* Location list. */
+ PROP_LOCLIST, /* Location list. */
+ PROP_VARIANT_PARTS, /* Variant parts. */
+ PROP_TYPE, /* Type. */
};
union dynamic_prop_data
@@ -450,6 +535,21 @@ union dynamic_prop_data
/* Storage for dynamic property. */
void *baton;
+
+ /* Storage of variant parts for a type. A type with variant parts
+ has all its fields "linearized" -- stored in a single field
+ array, just as if they had all been declared that way. The
+ variant parts are attached via a dynamic property, and then are
+ used to control which fields end up in the final type during
+ dynamic type resolution. */
+
+ const gdb::array_view<variant_part> *variant_parts;
+
+ /* Once a variant type is resolved, we may want to be able to go
+ from the resolved type to the original type. In this case we
+ rewrite the property's kind and set this field. */
+
+ struct type *original_type;
};
/* * Used to store a dynamic property. */
@@ -493,6 +593,9 @@ enum dynamic_prop_node_kind
/* A property holding information about a discriminated union. */
DYN_PROP_DISCRIMINATED,
+
+ /* A property holding variant parts. */
+ DYN_PROP_VARIANT_PARTS,
};
/* * List for dynamic type attributes. */