gdb/fortran: add support for accessing fields of extended types

Fortran 2003 supports type extension.  This patch allows access
to inherited members by using their fully qualified name as described
in the Fortran standard.

In doing so the patch also fixes a bug in GDB when trying to access the
members of a base class in a derived class via the derived class' base
class member.

This patch fixes PR22497 and PR26373 on GDB side.

Using the example Fortran program from PR22497

program mvce
  implicit none

  type :: my_type
     integer :: my_int
  end type my_type

  type, extends(my_type) :: extended_type
  end type extended_type

  type(my_type) :: foo
  type(extended_type) :: bar

  foo%my_int = 0
  bar%my_int = 1

  print*, foo, bar

end program mvce

and running this with GDB and setting a BP at 17:

Before:
(gdb) p bar%my_type
A syntax error in expression, near `my_type'.
(gdb) p bar%my_int
There is no member named my_int.
(gdb) p bar%my_type%my_int
A syntax error in expression, near `my_type%my_int'.
(gdb) p bar
$1 = ( my_type = ( my_int = 1 ) )

After:
(gdb) p bar%my_type
$1 = ( my_int = 1 )
(gdb) p bar%my_int
$2 = 1                 # this line requires DW_TAG_inheritance to work
(gdb) p bar%my_type%my_int
$3 = 1
(gdb) p bar
$4 = ( my_type = ( my_int = 1 ) )

In the above example "p bar%my_int" requires the compiler to emit
information about the inheritance relationship between extended_type
and my_type which gfortran and flang currently do not de.  The
respective issue gcc/49475 has been put as kfail.

Co-authored-by: Nils-Christian Kempke <nils-christian.kempke@intel.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=26373
     https://sourceware.org/bugzilla/show_bug.cgi?id=22497
This commit is contained in:
Bernhard Heckel
2022-04-05 17:44:46 +02:00
committed by Nils-Christian Kempke
parent 916c9be4a3
commit 87e10e9c28
4 changed files with 242 additions and 2 deletions

View File

@@ -808,8 +808,11 @@ nonempty_typelist
}
;
name : NAME
{ $$ = $1.stoken; }
name
: NAME
{ $$ = $1.stoken; }
| TYPENAME
{ $$ = $1.stoken; }
;
name_not_typename : NAME

View File

@@ -0,0 +1,159 @@
# Copyright 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/>.
standard_testfile ".f90"
load_lib "fortran.exp"
if { [skip_fortran_tests] } {
return -1
}
if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \
{debug f90 quiet}] } {
return -1
}
if ![fortran_runto_main] {
perror "could not run to main"
return -1
}
# Depending on the compiler being used, the type names can be printed differently.
set real [fortran_real4]
set logical [fortran_logical4]
set line1 [gdb_get_line_number "! Before vla allocation"]
gdb_breakpoint $line1
gdb_continue_to_breakpoint "line1" ".*$srcfile:$line1.*"
gdb_test "whatis wp_vla" "type = Type waypoint, allocatable \\(:\\)" \
"whatis wp_vla before allocation"
set line2 [gdb_get_line_number "! After value assignment"]
gdb_breakpoint $line2
gdb_continue_to_breakpoint "line2" ".*$srcfile:$line2.*"
# test print of wp
set test "p wp%coo"
gdb_test_multiple "$test" "$test" {
-re " = \\(1, 2, 1\\)\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named coo.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "p wp%point%coo" " = \\(1, 2, 1\\)"
gdb_test "p wp%point" " = \\( coo = \\(1, 2, 1\\) \\)"
gdb_test "p wp" " = \\( point = \\( coo = \\(1, 2, 1\\) \\), angle = 100 \\)"
gdb_test "whatis wp" "type = Type waypoint"
gdb_test "ptype wp" \
[multi_line "type = Type waypoint" \
" Type point :: point" \
" $real :: angle" \
"End Type waypoint"]
set test "ptype wp%coo"
gdb_test_multiple "$test" "$test" {
-re "$real \\(3\\)\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named coo.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "ptype wp%point%coo" "$real \\(3\\)"
# test print of fwp
set test "p fwp%coo"
gdb_test_multiple "$test" "$test" {
-re " = \\(1, 2, 2\\)\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named coo.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "p fwp%waypoint%point%coo" " = \\(1, 2, 2\\)"
gdb_test "p fwp%waypoint%point" " = \\( coo = \\(1, 2, 2\\) \\)"
gdb_test "p fwp%waypoint" \
" = \\( point = \\( coo = \\(1, 2, 2\\) \\), angle = 10 \\)"
gdb_test "p fwp" \
" = \\( waypoint = \\( point = \\( coo = \\(1, 2, 2\\) \\), angle = 10 \\), is_fancy = \.TRUE\. \\)"
set test "p fwp%angle"
gdb_test_multiple "$test" "$test" {
-re " = 10\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named angle.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "whatis fwp" "type = Type fancywaypoint"
gdb_test "ptype fwp" \
[multi_line "type = Type fancywaypoint" \
" Type waypoint :: waypoint" \
" $logical :: is_fancy" \
"End Type fancywaypoint"]
set test "ptype fwp%coo"
gdb_test_multiple "$test" "$test" {
-re "$real \\(3\\)\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named coo.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "ptype fwp%waypoint%point%coo" "$real \\(3\\)"
# test print of wp_vla
set test "p wp_vla(1)%coo"
gdb_test_multiple "$test" "$test" {
-re " = \\(10, 12, 10\\)\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named coo.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "p wp_vla(1)%point%coo" " = \\(10, 12, 10\\)"
gdb_test "p wp_vla(1)%point" " = \\( coo = \\(10, 12, 10\\) \\)"
gdb_test "p wp_vla(1)" " = \\( point = \\( coo = \\(10, 12, 10\\) \\), angle = 101 \\)"
gdb_test "whatis wp_vla" "type = Type waypoint, allocatable \\(3\\)" \
"whatis wp_vla after allocation"
gdb_test "ptype wp_vla" \
[multi_line "type = Type waypoint" \
" Type point :: point" \
" $real :: angle" \
"End Type waypoint, allocatable \\(3\\)"]
set test "ptype wp_vla(1)%coo"
gdb_test_multiple "$test" "$test" {
-re "$real \\(3\\)\r\n$gdb_prompt $" {
pass "$test"
}
-re "There is no member named coo.\r\n$gdb_prompt $" {
kfail "gcc/49475" "$test"
}
}
gdb_test "ptype wp_vla(1)%point%coo" "$real \\(3\\)"

View File

@@ -0,0 +1,69 @@
! Copyright 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/>.
! Test fortran extends feature (also for chained extends).
module testmod
implicit none
type :: point
real :: coo(3)
end type
type, extends(point) :: waypoint
real :: angle
end type
type, extends(waypoint) :: fancywaypoint
logical :: is_fancy
end type
end module
program testprog
use testmod
implicit none
logical l
type(waypoint) :: wp
type(fancywaypoint) :: fwp
type(waypoint), allocatable :: wp_vla(:)
l = .FALSE.
allocate(wp_vla(3)) ! Before vla allocation
l = allocated(wp_vla) ! After vla allocation
wp%angle = 100.00
wp%coo(:) = 1.00
wp%coo(2) = 2.00
fwp%is_fancy = .TRUE.
fwp%angle = 10.00
fwp%coo(:) = 2.00
fwp%coo(1) = 1.00
wp_vla(1)%angle = 101.00
wp_vla(1)%coo(:) = 10.00
wp_vla(1)%coo(2) = 12.00
wp_vla(2)%angle = 102.00
wp_vla(2)%coo(:) = 20.00
wp_vla(2)%coo(2) = 22.00
wp_vla(3)%angle = 103.00
wp_vla(3)%coo(:) = 30.00
wp_vla(3)%coo(2) = 32.00
print *, wp, wp_vla, fwp ! After value assignment
end program

View File

@@ -2374,6 +2374,15 @@ value_struct_elt (struct value **argp,
if (v)
return v;
if (current_language->la_language == language_fortran)
{
/* If it is not a field it is the type name of an inherited
structure. */
v = search_struct_field (name, *argp, t, 1);
if (v)
return v;
}
/* C++: If it was not found as a data field, then try to
return it as a pointer to a method. */
v = search_struct_method (name, argp, args, 0,