aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/dwarf2/read.c19
-rw-r--r--gdb/gdbtypes.c125
-rw-r--r--gdb/gdbtypes.h7
-rw-r--r--gdb/testsuite/gdb.fortran/assumedrank.exp86
-rw-r--r--gdb/testsuite/gdb.fortran/assumedrank.f9041
5 files changed, 263 insertions, 15 deletions
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 5c02d56..68c73c6 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -7694,6 +7694,7 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
add_partial_enumeration (pdi, cu);
break;
case DW_TAG_base_type:
+ case DW_TAG_generic_subrange:
case DW_TAG_subrange_type:
/* File scope base type definitions are added to the partial
symbol table. */
@@ -8020,6 +8021,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
case DW_TAG_typedef:
case DW_TAG_base_type:
case DW_TAG_subrange_type:
+ case DW_TAG_generic_subrange:
psymbol.domain = VAR_DOMAIN;
psymbol.aclass = LOC_TYPEDEF;
where = psymbol_placement::STATIC;
@@ -9722,6 +9724,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)
/* FALLTHROUGH */
case DW_TAG_base_type:
case DW_TAG_subrange_type:
+ case DW_TAG_generic_subrange:
case DW_TAG_typedef:
/* Add a typedef symbol for the type definition, if it has a
DW_AT_name. */
@@ -16687,7 +16690,8 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
child_die = die->child;
while (child_die && child_die->tag)
{
- if (child_die->tag == DW_TAG_subrange_type)
+ if (child_die->tag == DW_TAG_subrange_type
+ || child_die->tag == DW_TAG_generic_subrange)
{
struct type *child_type = read_type_die (child_die, cu);
@@ -19009,6 +19013,7 @@ is_type_tag_for_partial (int tag, enum language lang)
case DW_TAG_enumeration_type:
case DW_TAG_structure_type:
case DW_TAG_subrange_type:
+ case DW_TAG_generic_subrange:
case DW_TAG_typedef:
case DW_TAG_union_type:
return 1;
@@ -19142,6 +19147,7 @@ load_partial_dies (const struct die_reader_specs *reader,
&& ((pdi.tag == DW_TAG_typedef && !pdi.has_children)
|| pdi.tag == DW_TAG_base_type
|| pdi.tag == DW_TAG_array_type
+ || pdi.tag == DW_TAG_generic_subrange
|| pdi.tag == DW_TAG_subrange_type))
{
if (building_psymtab && pdi.raw_name != NULL)
@@ -22072,6 +22078,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
case DW_TAG_array_type:
case DW_TAG_base_type:
case DW_TAG_subrange_type:
+ case DW_TAG_generic_subrange:
sym->set_aclass_index (LOC_TYPEDEF);
sym->set_domain (VAR_DOMAIN);
list_to_add = cu->list_in_scope;
@@ -22565,6 +22572,7 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
case DW_TAG_typedef:
this_type = read_typedef (die, cu);
break;
+ case DW_TAG_generic_subrange:
case DW_TAG_subrange_type:
this_type = read_subrange_type (die, cu);
break;
@@ -24848,6 +24856,15 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
type->add_dyn_prop (DYN_PROP_ASSOCIATED, prop);
}
+ /* Read DW_AT_rank and set in type. */
+ attr = dwarf2_attr (die, DW_AT_rank, cu);
+ if (attr != NULL)
+ {
+ struct type *prop_type = cu->addr_sized_int_type (false);
+ if (attr_to_dynamic_prop (attr, die, cu, &prop, prop_type))
+ type->add_dyn_prop (DYN_PROP_RANK, prop);
+ }
+
/* Read DW_AT_data_location and set in type. */
if (!skip_data_location)
{
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index ae3b4cd..2623278 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -2199,7 +2199,7 @@ static struct type *resolve_dynamic_type_internal
static struct type *
resolve_dynamic_range (struct type *dyn_range_type,
struct property_addr_info *addr_stack,
- bool resolve_p = true)
+ int rank, bool resolve_p = true)
{
CORE_ADDR value;
struct type *static_range_type, *static_target_type;
@@ -2208,13 +2208,15 @@ resolve_dynamic_range (struct type *dyn_range_type,
gdb_assert (dyn_range_type->code () == TYPE_CODE_RANGE);
const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
- if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
+ if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value,
+ { (CORE_ADDR) rank }))
low_bound.set_const_val (value);
else
low_bound.set_undefined ();
prop = &dyn_range_type->bounds ()->high;
- if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
+ if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value,
+ { (CORE_ADDR) rank }))
{
high_bound.set_const_val (value);
@@ -2227,7 +2229,8 @@ resolve_dynamic_range (struct type *dyn_range_type,
bool byte_stride_p = dyn_range_type->bounds ()->flag_is_byte_stride;
prop = &dyn_range_type->bounds ()->stride;
- if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
+ if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value,
+ { (CORE_ADDR) rank }))
{
stride.set_const_val (value);
@@ -2258,18 +2261,29 @@ resolve_dynamic_range (struct type *dyn_range_type,
return static_range_type;
}
-/* Resolves dynamic bound values of an array or string type TYPE to static
- ones. ADDR_STACK is a stack of struct property_addr_info to be used if
- needed during the dynamic resolution.
+/* Helper function for resolve_dynamic_array_or_string. This function
+ resolves the properties for a single array at RANK within a nested array
+ of arrays structure. The RANK value is always greater than 0, and
+ starts at it's maximum value and goes down by 1 for each recursive call
+ to this function. So, for a 3-dimensional array, the first call to this
+ function has RANK == 3, then we call ourselves recursively with RANK ==
+ 2, than again with RANK == 1, and at that point we should return.
+
+ TYPE is updated as the dynamic properties are resolved, and so, should
+ be a copy of the dynamic type, rather than the original dynamic type
+ itself.
+
+ ADDR_STACK is a stack of struct property_addr_info to be used if needed
+ during the dynamic resolution.
When RESOLVE_P is true then the dynamic properties of TYPE are
evaluated, otherwise the dynamic properties of TYPE are not evaluated,
instead we assume the array is not allocated/associated yet. */
static struct type *
-resolve_dynamic_array_or_string (struct type *type,
- struct property_addr_info *addr_stack,
- bool resolve_p = true)
+resolve_dynamic_array_or_string_1 (struct type *type,
+ struct property_addr_info *addr_stack,
+ int rank, bool resolve_p)
{
CORE_ADDR value;
struct type *elt_type;
@@ -2283,7 +2297,9 @@ resolve_dynamic_array_or_string (struct type *type,
gdb_assert (type->code () == TYPE_CODE_ARRAY
|| type->code () == TYPE_CODE_STRING);
- type = copy_type (type);
+ /* The outer resolve_dynamic_array_or_string should ensure we always have
+ a rank of at least 1 when we get here. */
+ gdb_assert (rank > 0);
/* Resolve the allocated and associated properties before doing anything
else. If an array is not allocated or not associated then (at least
@@ -2313,11 +2329,16 @@ resolve_dynamic_array_or_string (struct type *type,
}
range_type = check_typedef (type->index_type ());
- range_type = resolve_dynamic_range (range_type, addr_stack, resolve_p);
+ range_type
+ = resolve_dynamic_range (range_type, addr_stack, rank, resolve_p);
ary_dim = check_typedef (TYPE_TARGET_TYPE (type));
if (ary_dim != NULL && ary_dim->code () == TYPE_CODE_ARRAY)
- elt_type = resolve_dynamic_array_or_string (ary_dim, addr_stack, resolve_p);
+ {
+ ary_dim = copy_type (ary_dim);
+ elt_type = resolve_dynamic_array_or_string_1 (ary_dim, addr_stack,
+ rank - 1, resolve_p);
+ }
else
elt_type = TYPE_TARGET_TYPE (type);
@@ -2345,6 +2366,78 @@ resolve_dynamic_array_or_string (struct type *type,
bit_stride);
}
+/* Resolve an array or string type with dynamic properties, return a new
+ type with the dynamic properties resolved to actual values. The
+ ADDR_STACK represents the location of the object being resolved. */
+
+static struct type *
+resolve_dynamic_array_or_string (struct type *type,
+ struct property_addr_info *addr_stack)
+{
+ CORE_ADDR value;
+ int rank = 0;
+
+ /* For dynamic type resolution strings can be treated like arrays of
+ characters. */
+ gdb_assert (type->code () == TYPE_CODE_ARRAY
+ || type->code () == TYPE_CODE_STRING);
+
+ type = copy_type (type);
+
+ /* Resolve the rank property to get rank value. */
+ struct dynamic_prop *prop = TYPE_RANK_PROP (type);
+ if (dwarf2_evaluate_property (prop, nullptr, addr_stack, &value))
+ {
+ prop->set_const_val (value);
+ rank = value;
+
+ if (rank == 0)
+ {
+ /* The dynamic property list juggling below was from the original
+ patch. I don't understand what this is all about, so I've
+ commented it out for now and added the following error. */
+ error (_("failed to resolve dynamic array rank"));
+ }
+ else if (type->code () == TYPE_CODE_STRING && rank != 1)
+ {
+ /* What would this even mean? A string with a dynamic rank
+ greater than 1. */
+ error (_("unable to handle string with dynamic rank greater than 1"));
+ }
+ else if (rank > 1)
+ {
+ /* Arrays with dynamic rank are initially just an array type
+ with a target type that is the array element.
+
+ However, now we know the rank of the array we need to build
+ the array of arrays structure that GDB expects, that is we
+ need an array type that has a target which is an array type,
+ and so on, until eventually, we have the element type at the
+ end of the chain. Create all the additional array types here
+ by copying the top level array type. */
+ struct type *element_type = TYPE_TARGET_TYPE (type);
+ struct type *rank_type = type;
+ for (int i = 1; i < rank; i++)
+ {
+ TYPE_TARGET_TYPE (rank_type) = copy_type (rank_type);
+ rank_type = TYPE_TARGET_TYPE (rank_type);
+ }
+ TYPE_TARGET_TYPE (rank_type) = element_type;
+ }
+ }
+ else
+ {
+ rank = 1;
+
+ for (struct type *tmp_type = check_typedef (TYPE_TARGET_TYPE (type));
+ tmp_type->code () == TYPE_CODE_ARRAY;
+ tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type)))
+ ++rank;
+ }
+
+ return resolve_dynamic_array_or_string_1 (type, addr_stack, rank, true);
+}
+
/* Resolve dynamic bounds of members of the union TYPE to static
bounds. ADDR_STACK is a stack of struct property_addr_info
to be used if needed during the dynamic resolution. */
@@ -2730,7 +2823,11 @@ resolve_dynamic_type_internal (struct type *type,
break;
case TYPE_CODE_RANGE:
- resolved_type = resolve_dynamic_range (type, addr_stack);
+ /* Pass 1 for the rank value here. The assumption is that this
+ rank value is not actually required for the resolution of the
+ dynamic range, otherwise, we'd be resolving this range within
+ the context of a dynamic array. */
+ resolved_type = resolve_dynamic_range (type, addr_stack, 1);
break;
case TYPE_CODE_UNION:
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 24e64e3..769328c 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -571,6 +571,10 @@ enum dynamic_prop_node_kind
/* A property holding variant parts. */
DYN_PROP_VARIANT_PARTS,
+ /* A property representing DW_AT_rank. The presence of this attribute
+ indicates that the object is of assumed rank array type. */
+ DYN_PROP_RANK,
+
/* A property holding the size of the type. */
DYN_PROP_BYTE_SIZE,
};
@@ -2088,6 +2092,7 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
#define TYPE_RVALUE_REFERENCE_TYPE(thistype) (thistype)->rvalue_reference_type
#define TYPE_CHAIN(thistype) (thistype)->chain
+#define TYPE_DYN_PROP(thistype) TYPE_MAIN_TYPE(thistype)->dyn_prop_list
/* * Note that if thistype is a TYPEDEF type, you have to call check_typedef.
But check_typedef does set the TYPE_LENGTH of the TYPEDEF type,
so you only have to call check_typedef once. Since allocate_value
@@ -2130,6 +2135,8 @@ extern bool set_type_align (struct type *, ULONGEST);
((thistype)->dyn_prop (DYN_PROP_ALLOCATED))
#define TYPE_ASSOCIATED_PROP(thistype) \
((thistype)->dyn_prop (DYN_PROP_ASSOCIATED))
+#define TYPE_RANK_PROP(thistype) \
+ ((thistype)->dyn_prop (DYN_PROP_RANK))
/* C++ */
diff --git a/gdb/testsuite/gdb.fortran/assumedrank.exp b/gdb/testsuite/gdb.fortran/assumedrank.exp
new file mode 100644
index 0000000..ac5159c
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/assumedrank.exp
@@ -0,0 +1,86 @@
+# Copyright 2021-2022 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/> .
+
+# Testing GDB's implementation of ASSUMED RANK arrays.
+
+if {[skip_fortran_tests]} { return -1 }
+
+standard_testfile ".f90"
+load_lib fortran.exp
+
+# Only gcc version >=11 supports assumed rank arrays.
+if { [test_compiler_info gcc*] &&
+ ![test_compiler_info {gcc-1[1-9]-*}]} {
+ untested "compiler does not support assumed rank"
+ return -1
+}
+
+if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \
+ {debug f90 additional_flags=-gdwarf-5}]} {
+ return -1
+}
+
+if ![fortran_runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Test Breakpoint"]
+gdb_breakpoint [gdb_get_line_number "Final Breakpoint"]
+
+# We place a limit on the number of tests that can be run, just in
+# case something goes wrong, and GDB gets stuck in an loop here.
+set found_final_breakpoint false
+set test_count 0
+while { $test_count < 500 } {
+ with_test_prefix "test $test_count" {
+ incr test_count
+
+ gdb_test_multiple "continue" "continue" {
+ -re -wrap "! Test Breakpoint" {
+ # We can run a test from here.
+ }
+ -re "! Final Breakpoint" {
+ # We're done with the tests.
+ set found_final_breakpoint true
+ }
+ }
+
+ if ($found_final_breakpoint) {
+ break
+ }
+
+ # First grab the expected answer.
+ set answer [get_valueof "" "rank(answer)" "**unknown**"]
+
+ # Now move up a frame and figure out a command for us to run
+ # as a test.
+ set command ""
+ gdb_test_multiple "up" "up" {
+ -re -wrap "\r\n\[0-9\]+\[ \t\]+call test_rank (\[^\r\n\]+)" {
+ set command $expect_out(1,string)
+ }
+ }
+
+ gdb_assert { ![string equal $command ""] } "found a command to run"
+
+ gdb_test "p rank($command)" " = ($answer)"
+ }
+}
+
+# Ensure we reached the final breakpoint. If more tests have been added
+# to the test script, and this starts failing, then the safety 'while'
+# loop above might need to be increased.
+gdb_assert {$found_final_breakpoint} "ran all compiled in tests"
diff --git a/gdb/testsuite/gdb.fortran/assumedrank.f90 b/gdb/testsuite/gdb.fortran/assumedrank.f90
new file mode 100644
index 0000000..16f2ee7
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/assumedrank.f90
@@ -0,0 +1,41 @@
+! Copyright 2021-2022 Free Software Foundation, Inc.
+!
+! This program is free software; you can redistribute it and/or modify
+! it under the terms of the GNU General Public License as published by
+! the Free Software Foundation; either version 3 of the License, or
+! (at your option) any later version.
+!
+! This program is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+! GNU General Public License for more details.
+!
+! You should have received a copy of the GNU General Public License
+! along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+!
+! Start of test program.
+!
+
+PROGRAM arank
+
+ REAL :: array1(10)
+ REAL :: array2(1, 2)
+ REAL :: array3(3, 4, 5)
+ REAL :: array4(4, 5, 6, 7)
+
+ call test_rank (array1)
+ call test_rank (array2)
+ call test_rank (array3)
+ call test_rank (array4)
+
+ print *, "" ! Final Breakpoint
+
+CONTAINS
+
+ SUBROUTINE test_rank(answer)
+ REAL :: answer(..)
+ print *, RANK(answer) ! Test Breakpoint
+ END SUBROUTINE test_rank
+
+END PROGRAM arank