diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c1dc2d0f7c5..711f6a89ea8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2015-05-15 Jerome Guitton + + * ada-lang.c (ada_value_ptr_subscript): Use enum position of + index to get element instead of enum value. + (ada_value_slice_from_ptr, ada_value_slice): Use enum position + of index to compute length, but enum values to compute bounds. + (ada_array_length): Use enum position of index instead of enum value. + (pos_atr): Move position computation to... + (ada_evaluate_subexp): Use enum values to compute bounds. + * gdbtypes.c (discrete_position): ...this new function. + * gdbtypes.h (discrete_position): New function declaration. + * valprint.c (val_print_array_elements): Call discrete_position + to handle array indexed by non-contiguous enumeration types. + 2015-05-15 Jerome Guitton * ada-lang.c (find_parallel_type_by_descriptive_type): diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 02d82ef48cd..f7891082abb 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -2765,13 +2765,15 @@ ada_value_ptr_subscript (struct value *arr, int arity, struct value **ind) for (k = 0; k < arity; k += 1) { LONGEST lwb, upb; + struct value *lwb_value; if (TYPE_CODE (type) != TYPE_CODE_ARRAY) error (_("too many subscripts (%d expected)"), k); arr = value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)), value_copy (arr)); get_discrete_bounds (TYPE_INDEX_TYPE (type), &lwb, &upb); - arr = value_ptradd (arr, pos_atr (ind[k]) - lwb); + lwb_value = value_from_longest (value_type(ind[k]), lwb); + arr = value_ptradd (arr, pos_atr (ind[k]) - pos_atr (lwb_value)); type = TYPE_TARGET_TYPE (type); } @@ -2779,24 +2781,34 @@ ada_value_ptr_subscript (struct value *arr, int arity, struct value **ind) } /* Given that ARRAY_PTR is a pointer or reference to an array of type TYPE (the - actual type of ARRAY_PTR is ignored), returns the Ada slice of HIGH-LOW+1 - elements starting at index LOW. The lower bound of this array is LOW, as - per Ada rules. */ + actual type of ARRAY_PTR is ignored), returns the Ada slice of + HIGH'Pos-LOW'Pos+1 elements starting at index LOW. The lower bound of + this array is LOW, as per Ada rules. */ static struct value * ada_value_slice_from_ptr (struct value *array_ptr, struct type *type, int low, int high) { struct type *type0 = ada_check_typedef (type); - CORE_ADDR base = value_as_address (array_ptr) - + ((low - ada_discrete_type_low_bound (TYPE_INDEX_TYPE (type0))) - * TYPE_LENGTH (TYPE_TARGET_TYPE (type0))); + struct type *base_index_type = TYPE_TARGET_TYPE (TYPE_INDEX_TYPE (type0)); struct type *index_type - = create_static_range_type (NULL, - TYPE_TARGET_TYPE (TYPE_INDEX_TYPE (type0)), - low, high); + = create_static_range_type (NULL, base_index_type, low, high); struct type *slice_type = create_array_type (NULL, TYPE_TARGET_TYPE (type0), index_type); + int base_low = ada_discrete_type_low_bound (TYPE_INDEX_TYPE (type0)); + LONGEST base_low_pos, low_pos; + CORE_ADDR base; + if (!discrete_position (base_index_type, low, &low_pos) + || !discrete_position (base_index_type, base_low, &base_low_pos)) + { + warning (_("unable to get positions in slice, use bounds instead")); + low_pos = low; + base_low_pos = base_low; + } + + base = value_as_address (array_ptr) + + ((low_pos - base_low_pos) + * TYPE_LENGTH (TYPE_TARGET_TYPE (type0))); return value_at_lazy (slice_type, base); } @@ -2805,12 +2817,23 @@ static struct value * ada_value_slice (struct value *array, int low, int high) { struct type *type = ada_check_typedef (value_type (array)); + struct type *base_index_type = TYPE_TARGET_TYPE (TYPE_INDEX_TYPE (type)); struct type *index_type = create_static_range_type (NULL, TYPE_INDEX_TYPE (type), low, high); struct type *slice_type = create_array_type (NULL, TYPE_TARGET_TYPE (type), index_type); + LONGEST low_pos, high_pos; - return value_cast (slice_type, value_slice (array, low, high - low + 1)); + if (!discrete_position (base_index_type, low, &low_pos) + || !discrete_position (base_index_type, high, &high_pos)) + { + warning (_("unable to get positions in slice, use bounds instead")); + low_pos = low; + high_pos = high; + } + + return value_cast (slice_type, + value_slice (array, low, high_pos - low_pos + 1)); } /* If type is a record type in the form of a standard GNAT array @@ -3012,7 +3035,8 @@ ada_array_bound (struct value *arr, int n, int which) static LONGEST ada_array_length (struct value *arr, int n) { - struct type *arr_type; + struct type *arr_type, *index_type; + int low, high; if (TYPE_CODE (check_typedef (value_type (arr))) == TYPE_CODE_PTR) arr = value_ind (arr); @@ -3022,11 +3046,30 @@ ada_array_length (struct value *arr, int n) return ada_array_length (decode_constrained_packed_array (arr), n); if (ada_is_simple_array_type (arr_type)) - return (ada_array_bound_from_type (arr_type, n, 1) - - ada_array_bound_from_type (arr_type, n, 0) + 1); + { + low = ada_array_bound_from_type (arr_type, n, 0); + high = ada_array_bound_from_type (arr_type, n, 1); + } else - return (value_as_long (desc_one_bound (desc_bounds (arr), n, 1)) - - value_as_long (desc_one_bound (desc_bounds (arr), n, 0)) + 1); + { + low = value_as_long (desc_one_bound (desc_bounds (arr), n, 0)); + high = value_as_long (desc_one_bound (desc_bounds (arr), n, 1)); + } + + CHECK_TYPEDEF (arr_type); + index_type = TYPE_INDEX_TYPE (arr_type); + if (index_type != NULL) + { + struct type *base_type; + if (TYPE_CODE (index_type) == TYPE_CODE_RANGE) + base_type = TYPE_TARGET_TYPE (index_type); + else + base_type = index_type; + + low = pos_atr (value_from_longest (base_type, low)); + high = pos_atr (value_from_longest (base_type, high)); + } + return high - low + 1; } /* An empty array whose type is that of ARR_TYPE (an array type), @@ -8995,24 +9038,15 @@ pos_atr (struct value *arg) { struct value *val = coerce_ref (arg); struct type *type = value_type (val); + LONGEST result; if (!discrete_type_p (type)) error (_("'POS only defined on discrete types")); - if (TYPE_CODE (type) == TYPE_CODE_ENUM) - { - int i; - LONGEST v = value_as_long (val); + if (!discrete_position (type, value_as_long (val), &result)) + error (_("enumeration value is invalid: can't find 'POS")); - for (i = 0; i < TYPE_NFIELDS (type); i += 1) - { - if (v == TYPE_FIELD_ENUMVAL (type, i)) - return i; - } - error (_("enumeration value is invalid: can't find 'POS")); - } - else - return value_as_long (val); + return result; } static struct value * @@ -10613,8 +10647,8 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, low_bound_val = coerce_ref (low_bound_val); high_bound_val = coerce_ref (high_bound_val); - low_bound = pos_atr (low_bound_val); - high_bound = pos_atr (high_bound_val); + low_bound = value_as_long (low_bound_val); + high_bound = value_as_long (high_bound_val); if (noside == EVAL_SKIP) goto nosideret; diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 4bbfc753889..ca86fbd3c21 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1004,6 +1004,45 @@ get_array_bounds (struct type *type, LONGEST *low_bound, LONGEST *high_bound) return 1; } +/* Assuming that TYPE is a discrete type and VAL is a valid integer + representation of a value of this type, save the corresponding + position number in POS. + + Its differs from VAL only in the case of enumeration types. In + this case, the position number of the value of the first listed + enumeration literal is zero; the position number of the value of + each subsequent enumeration literal is one more than that of its + predecessor in the list. + + Return 1 if the operation was successful. Return zero otherwise, + in which case the value of POS is unmodified. +*/ + +int +discrete_position (struct type *type, LONGEST val, LONGEST *pos) +{ + if (TYPE_CODE (type) == TYPE_CODE_ENUM) + { + int i; + + for (i = 0; i < TYPE_NFIELDS (type); i += 1) + { + if (val == TYPE_FIELD_ENUMVAL (type, i)) + { + *pos = i; + return 1; + } + } + /* Invalid enumeration value. */ + return 0; + } + else + { + *pos = val; + return 1; + } +} + /* Create an array type using either a blank type supplied in RESULT_TYPE, or creating a new type, inheriting the objfile from RANGE_TYPE. diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 4275ee09b93..fd3bc0ed5be 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -1837,6 +1837,8 @@ extern int get_discrete_bounds (struct type *, LONGEST *, LONGEST *); extern int get_array_bounds (struct type *type, LONGEST *low_bound, LONGEST *high_bound); +extern int discrete_position (struct type *type, LONGEST val, LONGEST *pos); + extern int class_types_same_p (const struct type *, const struct type *); extern int is_ancestor (struct type *, struct type *); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 74559f4cf7b..e14630ead03 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-05-15 Joel Brobecker + + * gdb.ada/arr_enum_with_gap: New testcase. + 2015-05-15 Joel Brobecker * gdb.ada/byte_packed_arr: New testcase. diff --git a/gdb/valprint.c b/gdb/valprint.c index 9a70b2f208c..294c6a86e14 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -1626,7 +1626,7 @@ val_print_array_elements (struct type *type, { unsigned int things_printed = 0; unsigned len; - struct type *elttype, *index_type; + struct type *elttype, *index_type, *base_index_type; unsigned eltlen; /* Position of the array element we are examining to see whether it is repeated. */ @@ -1634,6 +1634,7 @@ val_print_array_elements (struct type *type, /* Number of repetitions we have detected so far. */ unsigned int reps; LONGEST low_bound, high_bound; + LONGEST low_pos, high_pos; elttype = TYPE_TARGET_TYPE (type); eltlen = TYPE_LENGTH (check_typedef (elttype)); @@ -1641,15 +1642,33 @@ val_print_array_elements (struct type *type, if (get_array_bounds (type, &low_bound, &high_bound)) { - /* The array length should normally be HIGH_BOUND - LOW_BOUND + 1. + if (TYPE_CODE (index_type) == TYPE_CODE_RANGE) + base_index_type = TYPE_TARGET_TYPE (index_type); + else + base_index_type = index_type; + + /* Non-contiguous enumerations types can by used as index types + in some languages (e.g. Ada). In this case, the array length + shall be computed from the positions of the first and last + literal in the enumeration type, and not from the values + of these literals. */ + if (!discrete_position (base_index_type, low_bound, &low_pos) + || !discrete_position (base_index_type, high_bound, &high_pos)) + { + warning (_("unable to get positions in array, use bounds instead")); + low_pos = low_bound; + high_pos = high_bound; + } + + /* The array length should normally be HIGH_POS - LOW_POS + 1. But we have to be a little extra careful, because some languages - such as Ada allow LOW_BOUND to be greater than HIGH_BOUND for + such as Ada allow LOW_POS to be greater than HIGH_POS for empty arrays. In that situation, the array length is just zero, not negative! */ - if (low_bound > high_bound) + if (low_pos > high_pos) len = 0; else - len = high_bound - low_bound + 1; + len = high_pos - low_pos + 1; } else {