[Ada] Allow assignment to wide string.

Given the following variable declaration...

   Www : Wide_String := "12345";

... this patch allows the following assignment to work:

   (gdb) set variable www := "qwert"

Without this patch, the debugger rejects the assignment because
the size of the array elements are different:

   (gdb) set www := "asdfg"
   Incompatible types in assignment

(on the lhs, we have an array of 2-bytes elements, and on the rhs,
we have a standard 1-byte string).

gdb/ChangeLog:

        * ada-lang.c (ada_same_array_size_p): New function.
        (ada_promote_array_of_integrals): New function.
        (coerce_for_assign): Add handling of arrays where the elements
        are integrals of a smaller size than the size of the target
        array element type.

gdb/testsuite/ChangeLog:

        * gdb.ada/set_wstr: New testcase.
This commit is contained in:
Joel Brobecker
2012-10-24 18:14:23 +00:00
parent 3256027470
commit d99dcf51e1
7 changed files with 233 additions and 3 deletions

View File

@ -8629,6 +8629,72 @@ cast_from_fixed (struct type *type, struct value *arg)
return value_from_double (type, val);
}
/* Given two array types T1 and T2, return nonzero iff both arrays
contain the same number of elements. */
static int
ada_same_array_size_p (struct type *t1, struct type *t2)
{
LONGEST lo1, hi1, lo2, hi2;
/* Get the array bounds in order to verify that the size of
the two arrays match. */
if (!get_array_bounds (t1, &lo1, &hi1)
|| !get_array_bounds (t2, &lo2, &hi2))
error (_("unable to determine array bounds"));
/* To make things easier for size comparison, normalize a bit
the case of empty arrays by making sure that the difference
between upper bound and lower bound is always -1. */
if (lo1 > hi1)
hi1 = lo1 - 1;
if (lo2 > hi2)
hi2 = lo2 - 1;
return (hi1 - lo1 == hi2 - lo2);
}
/* Assuming that VAL is an array of integrals, and TYPE represents
an array with the same number of elements, but with wider integral
elements, return an array "casted" to TYPE. In practice, this
means that the returned array is built by casting each element
of the original array into TYPE's (wider) element type. */
static struct value *
ada_promote_array_of_integrals (struct type *type, struct value *val)
{
struct type *elt_type = TYPE_TARGET_TYPE (type);
LONGEST lo, hi;
struct value *res;
LONGEST i;
/* Verify that both val and type are arrays of scalars, and
that the size of val's elements is smaller than the size
of type's element. */
gdb_assert (TYPE_CODE (type) == TYPE_CODE_ARRAY);
gdb_assert (is_integral_type (TYPE_TARGET_TYPE (type)));
gdb_assert (TYPE_CODE (value_type (val)) == TYPE_CODE_ARRAY);
gdb_assert (is_integral_type (TYPE_TARGET_TYPE (value_type (val))));
gdb_assert (TYPE_LENGTH (TYPE_TARGET_TYPE (type))
> TYPE_LENGTH (TYPE_TARGET_TYPE (value_type (val))));
if (!get_array_bounds (type, &lo, &hi))
error (_("unable to determine array bounds"));
res = allocate_value (type);
/* Promote each array element. */
for (i = 0; i < hi - lo + 1; i++)
{
struct value *elt = value_cast (elt_type, value_subscript (val, lo + i));
memcpy (value_contents_writeable (res) + (i * TYPE_LENGTH (elt_type)),
value_contents_all (elt), TYPE_LENGTH (elt_type));
}
return res;
}
/* Coerce VAL as necessary for assignment to an lval of type TYPE, and
return the converted value. */
@ -8653,9 +8719,21 @@ coerce_for_assign (struct type *type, struct value *val)
if (TYPE_CODE (type2) == TYPE_CODE_ARRAY
&& TYPE_CODE (type) == TYPE_CODE_ARRAY)
{
if (TYPE_LENGTH (type2) != TYPE_LENGTH (type)
|| TYPE_LENGTH (TYPE_TARGET_TYPE (type2))
!= TYPE_LENGTH (TYPE_TARGET_TYPE (type2)))
if (!ada_same_array_size_p (type, type2))
error (_("cannot assign arrays of different length"));
if (is_integral_type (TYPE_TARGET_TYPE (type))
&& is_integral_type (TYPE_TARGET_TYPE (type2))
&& TYPE_LENGTH (TYPE_TARGET_TYPE (type2))
< TYPE_LENGTH (TYPE_TARGET_TYPE (type)))
{
/* Allow implicit promotion of the array elements to
a wider type. */
return ada_promote_array_of_integrals (type, val);
}
if (TYPE_LENGTH (TYPE_TARGET_TYPE (type2))
!= TYPE_LENGTH (TYPE_TARGET_TYPE (type)))
error (_("Incompatible types in assignment"));
deprecated_set_value_type (val, type);
}