[commit/Ada] better handling for unchecked union types
Joel Brobecker
brobecker@adacore.com
Tue Sep 30 21:41:00 GMT 2008
Hello,
We realized a while ago that we were not handling unchecked union
types very well... Unchecked union types are variant records with
an Unchecked_Union pragma applied to them, which transforms them
into the C-like union. For instance:
type Discriminant is (First, Second, Third, Fourth);
type Variant (Discr : Discriminant := First) is record
Data : Integer;
case Discr is
when First =>
F : Integer;
when Second =>
S : Float;
E : Float;
when Third | Fourth =>
T : Boolean;
H : Boolean;
end case;
end record;
pragma Unchecked_Union (Variant);
Since the discriminant is no longer known, the debugger needs
to print the value of all branches, just like we do for C unions.
The attach patch fixes the various bugs we found.
2008-09-30 Paul Hilfinger <brobecker@adacore.com>
* ada-lang.c (ada_lookup_struct_elt_type): Handle case of a "naked"
variant branch.
(empty_record): Use INIT_CPLUS_SPECIFIC, since this field is not
supposed to be null. Fixes debugger segfaults.
(is_unchecked_variant): New function.
(to_fixed_variant_branch_type): Modify to leave unchecked unions
untouched.
(ada_template_to_fixed_record_type_1): Fix comment.
Tested on x86-linux. No regression.
Checked in.
--
Joel
-------------- next part --------------
Index: ada-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-lang.c,v
retrieving revision 1.174
diff -u -p -r1.174 ada-lang.c
--- ada-lang.c 30 Sep 2008 20:42:21 -0000 1.174
+++ ada-lang.c 30 Sep 2008 21:33:44 -0000
@@ -6403,9 +6403,19 @@ ada_lookup_struct_elt_type (struct type
for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1)
{
+ /* FIXME pnh 2008/01/26: We check for a field that is
+ NOT wrapped in a struct, since the compiler sometimes
+ generates these for unchecked variant types. Revisit
+ if the compiler changes this practice. */
+ char *v_field_name = TYPE_FIELD_NAME (field_type, j);
disp = 0;
- t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (field_type, j),
- name, 0, 1, &disp);
+ if (v_field_name != NULL
+ && field_name_match (v_field_name, name))
+ t = ada_check_typedef (TYPE_FIELD_TYPE (field_type, j));
+ else
+ t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (field_type, j),
+ name, 0, 1, &disp);
+
if (t != NULL)
{
if (dispp != NULL)
@@ -6442,6 +6452,20 @@ BadName:
}
/* Assuming that VAR_TYPE is the type of a variant part of a record (a union),
+ within a value of type OUTER_TYPE, return true iff VAR_TYPE
+ represents an unchecked union (that is, the variant part of a
+ record that is named in an Unchecked_Union pragma). */
+
+static int
+is_unchecked_variant (struct type *var_type, struct type *outer_type)
+{
+ char *discrim_name = ada_variant_discrim_name (var_type);
+ return (ada_lookup_struct_elt_type (outer_type, discrim_name, 0, 1, NULL)
+ == NULL);
+}
+
+
+/* Assuming that VAR_TYPE is the type of a variant part of a record (a union),
within a value of type OUTER_TYPE that is stored in GDB at
OUTER_VALADDR, determine which variant clause (field number in VAR_TYPE,
numbering from 0) is applicable. Returns -1 if none are. */
@@ -6812,6 +6836,7 @@ empty_record (struct objfile *objfile)
TYPE_CODE (type) = TYPE_CODE_STRUCT;
TYPE_NFIELDS (type) = 0;
TYPE_FIELDS (type) = NULL;
+ INIT_CPLUS_SPECIFIC (type);
TYPE_NAME (type) = "<empty>";
TYPE_TAG_NAME (type) = NULL;
TYPE_LENGTH (type) = 0;
@@ -6933,7 +6958,7 @@ ada_template_to_fixed_record_type_1 (str
}
/* We handle the variant part, if any, at the end because of certain
- odd cases in which it is re-ordered so as NOT the last field of
+ odd cases in which it is re-ordered so as NOT to be the last field of
the record. This can happen in the presence of representation
clauses. */
if (variant_field >= 0)
@@ -7180,7 +7205,8 @@ to_fixed_record_type (struct type *type0
union type. Any necessary discriminants' values should be in DVAL,
a record value. That is, this routine selects the appropriate
branch of the union at ADDR according to the discriminant value
- indicated in the union's type name. */
+ indicated in the union's type name. Returns VAR_TYPE0 itself if
+ it represents a variant subject to a pragma Unchecked_Union. */
static struct type *
to_fixed_variant_branch_type (struct type *var_type0, const gdb_byte *valaddr,
@@ -7200,6 +7226,8 @@ to_fixed_variant_branch_type (struct typ
if (templ_type != NULL)
var_type = templ_type;
+ if (is_unchecked_variant (var_type, value_type (dval)))
+ return var_type0;
which =
ada_which_variant_applies (var_type,
value_type (dval), value_contents (dval));
More information about the Gdb-patches
mailing list