Compare commits

...

4 Commits

Author SHA1 Message Date
Bernhard Heckel
bee226f9b2 Fortran: Document scope operator.
Document scope operator in GDB manual.

2016-08-10  Bernhard Heckel  <bernhard.heckel@intel.com>

gdb/Changelog:
	* doc/gdb.texinfo: Describe scope operator.

Change-Id: I15ff901b4a729f0994410a971bba639ebc361d2a
2016-12-23 12:20:09 +01:00
Bernhard Heckel
1c04575472 Fortran: Nested functions, add scope parameter.
In order to avoid name clashing in GDB, we add a scope
to nested subroutines. Enveloping function gives the
scope.

Change-Id: I7d424b1e3039613d938aae56ec1a3b3d1cdda744
2016-12-23 12:20:06 +01:00
Bernhard Heckel
671c004cc4 Fortran: Enable setting breakpoint on nested functions.
Like in Ada, we want to be able to set a breakpoint on
nested functions, called "contained routines" in Fortran.

2016-06-30  Bernhard Heckel  <bernhard.heckel@intel.com>

gdb/Changelog:
	* dwarf2read.c (todo)

gdb/Changelog:
	* gdb.fortran/nested-funcs.exp: Set breakpoint on contained routines.

Change-Id: I7f2897f8f3160c0d5618850273d87579cc2479c8
2016-12-23 12:20:04 +01:00
Bernhard Heckel
57ed8b65cc Dwarf: Fortran, support DW_TAG_entry_point.
Fortran provides additional entry-points to an subprogram.
Those entry-points may have only a subset of parameters
of the original subprogram as well.
Add support for parsing DW_TAG_entry_point's for Fortran.

2016-06-01  Bernhard Heckel  <bernhard.heckel@intel.com>

gdb/Changelog:
	* gdb/dwarf2read.c (add_partial_symbol): Handle DW_TAG_entry_point.
	(add_partial_entry_point): New.
	(add_partial_subprogram): Search for entry_points.
	(process_die): Handle DW_TAG_entry_point.
	(dwarf2_get_pc_bounds): Update low pc from DWARF.
	(load_partial_dies): Save DW_TAG_entry_point's.
	(load_partial_dies): Save DW_TAG_entry_point to hash table.
	(load_partial_dies): Look into child's of DW_TAG_sub_program
	for fortran.
	(new_symbol_full): Process DW_TAG_entry_point.
	(read_type_die_1): Handle DW_TAG_entry_point.

gdb/Testsuite/Changelog:
	* gdb.fortran/entry_point.f90: New.
	* gdb.fortran/entry_point.exp: New.

Change-Id: I886699802fc940cd9b995806c32a85a05cf57dc4
2016-12-23 12:20:01 +01:00
6 changed files with 328 additions and 7 deletions

3
gdb/doc/gdb.texinfo Normal file → Executable file
View File

@@ -15228,6 +15228,9 @@ The access component operator. Normally used to access elements in derived
types. Also suitable for unions. As unions aren't part of regular Fortran, types. Also suitable for unions. As unions aren't part of regular Fortran,
this can only happen when accessing a register that uses a gdbarch-defined this can only happen when accessing a register that uses a gdbarch-defined
union type. union type.
@item ::
The scope operator. Normally used to access variables in modules or to set breakpoints
on subroutines nested in modules or in other subroutines (internal subroutines).
@end table @end table
@node Fortran Defaults @node Fortran Defaults

View File

@@ -1425,6 +1425,10 @@ static void add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
static void add_partial_enumeration (struct partial_die_info *enum_pdi, static void add_partial_enumeration (struct partial_die_info *enum_pdi,
struct dwarf2_cu *cu); struct dwarf2_cu *cu);
static void add_partial_entry_point (struct partial_die_info *pdi,
CORE_ADDR *lowpc, CORE_ADDR *highpc,
int need_pc, struct dwarf2_cu *cu);
static void add_partial_subprogram (struct partial_die_info *pdi, static void add_partial_subprogram (struct partial_die_info *pdi,
CORE_ADDR *lowpc, CORE_ADDR *highpc, CORE_ADDR *lowpc, CORE_ADDR *highpc,
int need_pc, struct dwarf2_cu *cu); int need_pc, struct dwarf2_cu *cu);
@@ -6817,6 +6821,7 @@ partial_die_parent_scope (struct partial_die_info *pdi,
return NULL; return NULL;
} }
/* Internal (nested) subroutines in Fortran get a prefix. */
if (pdi->tag == DW_TAG_enumerator) if (pdi->tag == DW_TAG_enumerator)
/* Enumerators should not get the name of the enumeration as a prefix. */ /* Enumerators should not get the name of the enumeration as a prefix. */
parent->scope = grandparent_scope; parent->scope = grandparent_scope;
@@ -6826,7 +6831,10 @@ partial_die_parent_scope (struct partial_die_info *pdi,
|| parent->tag == DW_TAG_class_type || parent->tag == DW_TAG_class_type
|| parent->tag == DW_TAG_interface_type || parent->tag == DW_TAG_interface_type
|| parent->tag == DW_TAG_union_type || parent->tag == DW_TAG_union_type
|| parent->tag == DW_TAG_enumeration_type) || parent->tag == DW_TAG_enumeration_type
|| (cu->language == language_fortran
&& parent->tag == DW_TAG_subprogram
&& pdi->tag == DW_TAG_subprogram))
{ {
if (grandparent_scope == NULL) if (grandparent_scope == NULL)
parent->scope = parent->name; parent->scope = parent->name;
@@ -6911,9 +6919,30 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
switch (pdi->tag) switch (pdi->tag)
{ {
case DW_TAG_entry_point:
addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);
/* DW_TAG_entry_point provides an additional entry_point to an
existing sub_program. Therefore, we inherit the "external"
attribute from the sub_program to which the entry_point
belongs to. */
if (pdi->die_parent->is_external)
add_psymbol_to_list (actual_name, strlen (actual_name),
built_actual_name != NULL,
VAR_DOMAIN, LOC_BLOCK,
&objfile->global_psymbols,
addr, cu->language, objfile);
else
add_psymbol_to_list (actual_name, strlen (actual_name),
built_actual_name != NULL,
VAR_DOMAIN, LOC_BLOCK,
&objfile->static_psymbols,
addr, cu->language, objfile);
break;
case DW_TAG_subprogram: case DW_TAG_subprogram:
addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr); addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);
if (pdi->is_external || cu->language == language_ada) if (pdi->is_external
|| cu->language == language_ada
|| cu->language == language_fortran)
{ {
/* brobecker/2007-12-26: Normally, only "external" DIEs are part /* brobecker/2007-12-26: Normally, only "external" DIEs are part
of the global scope. But in Ada, we want to be able to access of the global scope. But in Ada, we want to be able to access
@@ -7108,6 +7137,17 @@ add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu); scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);
} }
static void
add_partial_entry_point (struct partial_die_info *pdi,
CORE_ADDR *p_lowpc, CORE_ADDR *p_highpc,
int set_addrmap, struct dwarf2_cu *cu)
{
if (pdi->name == NULL)
complaint (&symfile_complaints, _("DW_TAG_entry_point have to have a name"));
else
add_partial_symbol (pdi, cu);
}
/* Read a partial die corresponding to a subprogram and create a partial /* Read a partial die corresponding to a subprogram and create a partial
symbol for that subprogram. When the CU language allows it, this symbol for that subprogram. When the CU language allows it, this
routine also defines a partial symbol for each nested subprogram routine also defines a partial symbol for each nested subprogram
@@ -7178,6 +7218,18 @@ add_partial_subprogram (struct partial_die_info *pdi,
pdi = pdi->die_sibling; pdi = pdi->die_sibling;
} }
} }
else if (cu->language == language_fortran)
{
pdi = pdi->die_child;
while (pdi != NULL)
{
if (pdi->tag == DW_TAG_entry_point)
add_partial_entry_point (pdi, lowpc, highpc, set_addrmap, cu);
else if (pdi->tag == DW_TAG_subprogram)
add_partial_subprogram (pdi, lowpc, highpc, set_addrmap, cu);
pdi = pdi->die_sibling;
}
}
} }
/* Read a partial die corresponding to an enumeration type. */ /* Read a partial die corresponding to an enumeration type. */
@@ -8283,6 +8335,12 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)
read_type_unit_scope (die, cu); read_type_unit_scope (die, cu);
break; break;
case DW_TAG_subprogram: case DW_TAG_subprogram:
/* Internal subprograms in Fortran get a prefix. */
if (cu->language == language_fortran
&& die->parent != NULL
&& die->parent->tag == DW_TAG_subprogram)
cu->processing_has_namespace_info = 1;
case DW_TAG_entry_point:
case DW_TAG_inlined_subroutine: case DW_TAG_inlined_subroutine:
read_func_scope (die, cu); read_func_scope (die, cu);
break; break;
@@ -12063,6 +12121,27 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
CORE_ADDR high = 0; CORE_ADDR high = 0;
enum pc_bounds_kind ret; enum pc_bounds_kind ret;
if (die->tag == DW_TAG_entry_point)
{
/* Entry_point is embedded in an subprogram. Therefore, we can use
the highpc from it's enveloping subprogram and get the
lowpc from DWARF. */
if (PC_BOUNDS_INVALID == dwarf2_get_pc_bounds (die->parent, lowpc, highpc, cu, pst))
return PC_BOUNDS_INVALID;
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
if (!attr)
{
complaint (&symfile_complaints,
_("DW_TAG_entry_point is missing DW_AT_low_pc"));
return PC_BOUNDS_INVALID;
}
low = attr_value_as_address (attr);
*lowpc = low;
return PC_BOUNDS_HIGH_LOW;
}
attr_high = dwarf2_attr (die, DW_AT_high_pc, cu); attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
if (attr_high) if (attr_high)
{ {
@@ -15632,6 +15711,7 @@ load_partial_dies (const struct die_reader_specs *reader,
&& abbrev->tag != DW_TAG_constant && abbrev->tag != DW_TAG_constant
&& abbrev->tag != DW_TAG_enumerator && abbrev->tag != DW_TAG_enumerator
&& abbrev->tag != DW_TAG_subprogram && abbrev->tag != DW_TAG_subprogram
&& abbrev->tag != DW_TAG_entry_point
&& abbrev->tag != DW_TAG_lexical_block && abbrev->tag != DW_TAG_lexical_block
&& abbrev->tag != DW_TAG_variable && abbrev->tag != DW_TAG_variable
&& abbrev->tag != DW_TAG_namespace && abbrev->tag != DW_TAG_namespace
@@ -15758,6 +15838,7 @@ load_partial_dies (const struct die_reader_specs *reader,
if (load_all if (load_all
|| abbrev->tag == DW_TAG_constant || abbrev->tag == DW_TAG_constant
|| abbrev->tag == DW_TAG_subprogram || abbrev->tag == DW_TAG_subprogram
|| abbrev->tag == DW_TAG_entry_point
|| abbrev->tag == DW_TAG_variable || abbrev->tag == DW_TAG_variable
|| abbrev->tag == DW_TAG_namespace || abbrev->tag == DW_TAG_namespace
|| part_die->is_declaration) || part_die->is_declaration)
@@ -15799,7 +15880,9 @@ load_partial_dies (const struct die_reader_specs *reader,
|| last_die->tag == DW_TAG_union_type)) || last_die->tag == DW_TAG_union_type))
|| (cu->language == language_ada || (cu->language == language_ada
&& (last_die->tag == DW_TAG_subprogram && (last_die->tag == DW_TAG_subprogram
|| last_die->tag == DW_TAG_lexical_block)))) || last_die->tag == DW_TAG_lexical_block))
|| (cu->language == language_fortran
&& last_die->tag == DW_TAG_subprogram)))
{ {
nesting_level++; nesting_level++;
parent_die = last_die; parent_die = last_die;
@@ -18440,13 +18523,28 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL; SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;
add_symbol_to_list (sym, cu->list_in_scope); add_symbol_to_list (sym, cu->list_in_scope);
break; break;
case DW_TAG_entry_point:
/* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
finish_block. */
SYMBOL_ACLASS_INDEX (sym) = LOC_BLOCK;
/* DW_TAG_entry_point provides an additional entry_point to an
existing sub_program. Therefore, we inherit the "external"
attribute from the sub_program to which the entry_point
belongs to. */
attr2 = dwarf2_attr (die->parent, DW_AT_external, cu);
if (attr2 && (DW_UNSND (attr2) != 0))
list_to_add = &global_symbols;
else
list_to_add = cu->list_in_scope;
break;
case DW_TAG_subprogram: case DW_TAG_subprogram:
/* SYMBOL_BLOCK_VALUE (sym) will be filled in later by /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
finish_block. */ finish_block. */
SYMBOL_ACLASS_INDEX (sym) = LOC_BLOCK; SYMBOL_ACLASS_INDEX (sym) = LOC_BLOCK;
attr2 = dwarf2_attr (die, DW_AT_external, cu); attr2 = dwarf2_attr (die, DW_AT_external, cu);
if ((attr2 && (DW_UNSND (attr2) != 0)) if ((attr2 && (DW_UNSND (attr2) != 0))
|| cu->language == language_ada) || cu->language == language_ada
|| cu->language == language_fortran)
{ {
/* Subprograms marked external are stored as a global symbol. /* Subprograms marked external are stored as a global symbol.
Ada subprograms, whether marked external or not, are always Ada subprograms, whether marked external or not, are always
@@ -19124,6 +19222,7 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
case DW_TAG_enumeration_type: case DW_TAG_enumeration_type:
this_type = read_enumeration_type (die, cu); this_type = read_enumeration_type (die, cu);
break; break;
case DW_TAG_entry_point:
case DW_TAG_subprogram: case DW_TAG_subprogram:
case DW_TAG_subroutine_type: case DW_TAG_subroutine_type:
case DW_TAG_inlined_subroutine: case DW_TAG_inlined_subroutine:
@@ -19450,6 +19549,19 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu)
return TYPE_TAG_NAME (parent_type); return TYPE_TAG_NAME (parent_type);
return ""; return "";
} }
case DW_TAG_subprogram:
/* Only internal subroutines in Fortran get a prefix with the name
of the parent's subroutine. */
if (cu->language == language_fortran)
{
if ((die->tag == DW_TAG_subprogram)
&& (dwarf2_name (parent, cu) != NULL))
return dwarf2_name (parent, cu);
else
return "";
}
else
return determine_prefix (parent, cu);
/* Fall through. */ /* Fall through. */
default: default:
return determine_prefix (parent, cu); return determine_prefix (parent, cu);

View File

@@ -0,0 +1,70 @@
# Copyright 2016 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/>.
if { [skip_fortran_tests] } { return -1 }
standard_testfile .f90
load_lib "fortran.exp"
if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug f90}]} {
return -1
}
if ![runto MAIN__] then {
perror "couldn't run to breakpoint MAIN__"
continue
}
# Test if we can set a breakpoint via entry-point name
set ept_name "foo"
gdb_breakpoint $ept_name
gdb_test "continue" \
[multi_line "Breakpoint $decimal, $ept_name \\(j=1, k=2, l=3, i1=4\\) at .*" \
".*"] \
"continue to breakpoint: $ept_name"
gdb_test "print j" "= 1" "print j, entered via $ept_name"
gdb_test "print k" "= 2" "print k, entered via $ept_name"
gdb_test "print l" "= 3" "print l, entered via $ept_name"
gdb_test "print i1" "= 4" "print i1, entered via $ept_name"
gdb_test "info args" \
[multi_line "j = 1" \
"k = 2" \
"l = 3" \
"i1 = 4"] \
"info args, entered via $ept_name"
# Test if we can set a breakpoint via function name
set ept_name "bar"
gdb_breakpoint $ept_name
gdb_test "continue" \
[multi_line "Breakpoint $decimal, $ept_name \\(i=4, j=5, k=6, i1=7\\) at .*" \
".*"] \
"continue to breakpoint: $ept_name"
gdb_test "print i" "= 4" "print i, entered via $ept_name"
gdb_test "print j" "= 5" "print j, entered via $ept_name"
gdb_test "print k" "= 6" "print k, entered via $ept_name"
gdb_test "print i1" "= 7" "print i1, entered via $ept_name"
set ept_name "tim"
gdb_breakpoint $ept_name
gdb_test "continue" \
[multi_line "Breakpoint $decimal, $ept_name \\(j=1\\) at .*" \
".*"] \
"continue to breakpoint: $ept_name"
gdb_test "print j" "= 1" "print j, entered via $ept_name"
gdb_test "info args" "j = 1" "info args, entered via $ept_name"

View File

@@ -0,0 +1,48 @@
! Copyright 2016 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/>.
program TestEntryPoint
call foo(1,2,3,4)
call bar(4,5,6,7)
call tim(1)
end program TestEntryPoint
subroutine bar(I,J,K,I1)
INTEGER I,J,K,L,I1
INTEGER A
REAL C
A = 0
C = 0.0
A = I + K + I1
goto 1000
entry foo(J,K,L,I1)
A = J + K + L + I1
200 C = J
goto 1000
entry tim(J)
goto 200
1000 A = C + 1
C = J * 1.5
return
end subroutine

View File

@@ -30,6 +30,10 @@ if ![runto MAIN__] then {
continue continue
} }
# Test if we can set a breakpoint in a nested function
gdb_breakpoint "testnestedfuncs::sub_nested_outer"
gdb_continue_to_breakpoint "testnestedfuncs::sub_nested_outer" ".*local_int = 19"
# Test if we can access local and # Test if we can access local and
# non-local variables defined one level up. # non-local variables defined one level up.
gdb_breakpoint [gdb_get_line_number "! BP_outer"] gdb_breakpoint [gdb_get_line_number "! BP_outer"]
@@ -39,10 +43,17 @@ gdb_test "set index = 42"
gdb_test "print index" "= 42" "print index at BP_outer, manipulated" gdb_test "print index" "= 42" "print index at BP_outer, manipulated"
gdb_test "print local_int" "= 19" "print local_int in outer function" gdb_test "print local_int" "= 19" "print local_int in outer function"
# Non-local variable should be affected in one frame up as well. # Non-local variable should be affected in one frame up as well.
gdb_test "up" gdb_test "up"
gdb_test "print index" "= 42" "print index at BP1, one frame up" gdb_test "print index" "= 42" "print index at BP1, one frame up"
# Test if we can set a breakpoint in a nested function
gdb_breakpoint "testnestedfuncs::sub_nested_inner"
gdb_continue_to_breakpoint "testnestedfuncs::sub_nested_inner" ".*local_int = 17"
# Test if we can access local and # Test if we can access local and
# non-local variables defined two level up. # non-local variables defined two level up.
gdb_breakpoint [gdb_get_line_number "! BP_inner"] gdb_breakpoint [gdb_get_line_number "! BP_inner"]
@@ -51,12 +62,29 @@ gdb_test "print index" "= 42" "print index at BP_inner"
gdb_test "print v_state%code" "= 61" "print v_state%code at BP_inner" gdb_test "print v_state%code" "= 61" "print v_state%code at BP_inner"
gdb_test "print local_int" "= 17" "print local_int in inner function" gdb_test "print local_int" "= 17" "print local_int in inner function"
# Test if local variable is still correct. # Test if local variable is still correct.
gdb_breakpoint [gdb_get_line_number "! BP_outer_2"] gdb_breakpoint [gdb_get_line_number "! BP_outer_2"]
gdb_continue_to_breakpoint "! BP_outer_2" ".*! BP_outer_2" gdb_continue_to_breakpoint "! BP_outer_2" ".*! BP_outer_2"
gdb_test "print local_int" "= 19" \ gdb_test "print local_int" "= 19" \
"print local_int in outer function, after sub_nested_inner" "print local_int in outer function, after sub_nested_inner"
# Test if we can set a breakpoint in public routine with the same name as the internal
gdb_breakpoint "sub_nested_outer"
gdb_continue_to_breakpoint "sub_nested_outer" ".*name = 'sub_nested_outer external'"
# Test if we can set a breakpoint in public routine with the same name as the internal
gdb_breakpoint "sub_with_sub_nested_outer::sub_nested_outer"
gdb_continue_to_breakpoint "sub_with_sub_nested_outer::sub_nested_outer" ".*local_int = 11"
# Test if we can set a breakpoint in public routine with the same name as the internal
gdb_breakpoint "mod1::sub_nested_outer"
gdb_continue_to_breakpoint "mod1::sub_nested_outer" ".*name = 'sub_nested_outer_mod1'"
# Sanity check in main. # Sanity check in main.
gdb_breakpoint [gdb_get_line_number "! BP_main"] gdb_breakpoint [gdb_get_line_number "! BP_main"]
gdb_continue_to_breakpoint "! BP_main" ".*! BP_main" gdb_continue_to_breakpoint "! BP_main" ".*! BP_main"

View File

@@ -13,8 +13,64 @@
! You should have received a copy of the GNU General Public License ! You should have received a copy of the GNU General Public License
! along with this program. If not, see <http://www.gnu.org/licenses/>. ! along with this program. If not, see <http://www.gnu.org/licenses/>.
program TestNestedFuncs
module mod1
integer :: var_i = 1
integer :: var_const
parameter (var_const = 20)
CONTAINS
SUBROUTINE sub_nested_outer
integer :: local_int
character (len=20) :: name
name = 'sub_nested_outer_mod1'
local_int = 11
END SUBROUTINE sub_nested_outer
end module mod1
! Public sub_nested_outer
SUBROUTINE sub_nested_outer
integer :: local_int
character (len=16) :: name
name = 'sub_nested_outer external'
local_int = 11
END SUBROUTINE sub_nested_outer
! Needed indirection to call public sub_nested_outer from main
SUBROUTINE sub_nested_outer_ind
character (len=20) :: name
name = 'sub_nested_outer_ind'
CALL sub_nested_outer
END SUBROUTINE sub_nested_outer_ind
! public routine with internal subroutine
SUBROUTINE sub_with_sub_nested_outer()
integer :: local_int
character (len=16) :: name
name = 'subroutine_with_int_sub'
local_int = 1
CALL sub_nested_outer ! Should call the internal fct
CONTAINS
SUBROUTINE sub_nested_outer
integer :: local_int
local_int = 11
END SUBROUTINE sub_nested_outer
END SUBROUTINE sub_with_sub_nested_outer
! Main
program TestNestedFuncs
USE mod1, sub_nested_outer_use_mod1 => sub_nested_outer
IMPLICIT NONE IMPLICIT NONE
TYPE :: t_State TYPE :: t_State
@@ -22,10 +78,14 @@ program TestNestedFuncs
END TYPE t_State END TYPE t_State
TYPE (t_State) :: v_state TYPE (t_State) :: v_state
integer index integer index, local_int
local_int = 14
index = 13 index = 13
CALL sub_nested_outer CALL sub_nested_outer ! Call internal sub_nested_outer
CALL sub_nested_outer_ind ! Call external sub_nested_outer via sub_nested_outer_ind
CALL sub_with_sub_nested_outer ! Call external routine with nested sub_nested_outer
CALL sub_nested_outer_use_mod1 ! Call sub_nested_outer imported via module
index = 11 ! BP_main index = 11 ! BP_main
v_state%code = 27 v_state%code = 27