我构建一个简单的案例来重现下面的问题。我不能再减少了。问题描述:我有3个类
清理
清理
,定义和实现过程:初始化、完成
和定义以下延迟过程:设置、free_resources、重置
;设置,free_resources,重置
定义变量(C类型的对象)的测试程序(test.f90),调用init
,然后完成对象上的过程。
源代码中调用的过程似乎与可执行文件中调用(运行)的过程不同:子例程调用在编译时被打乱。一个小的变化(对于gfortran 7.5.0)如删除类< code>B的过程< code>init上的< code>non_overridable会产生一个调用< code>init的无限循环(就像init和setup指向同一个过程一样)。这种循环行为可以通过代码中的其他一些小变化来重现。
我怀疑这个问题与延迟
和non_overridable
有关。除非我犯了一个错误,否则它看起来像是在 4.8.5 之后引入的 gfortran 中的一个错误。
预期产出:
Test: calling C%init
B::init, calling setup
C::setup
B::init done ...............
Test: calling C%finalize
B::finalize, calling free_resources
C::free_resources
B::finalize, calling cleanup
B::cleanup
B::finalize done ...................
Test:done.......................
我得到的是这个:
Test: calling C%init
B::init, calling setup
B::cleanup
B::init done ...............
Test: calling C%finalize
B::finalize, calling free_resources
C::setup
B::finalize, calling cleanup
B::cleanup
B::finalize done ...................
Test:done.......................
我尝试了以下版本的gfortran:
gfortran 6的结果(请参阅重置调用)
Test: calling C%init
B::init, calling setup
B::cleanup
B::init done ...............
Test: calling C%finalize
B::finalize, calling free_resources
C::reset
B::finalize, calling cleanup
B::cleanup
B::finalize done ...................
Test:done.......................
源代码:
$ cat A_Mod.f90
!
module A_Mod
implicit none
!
private
!
type, public, abstract :: A
private
logical :: status !< status of the object
contains
!
procedure, non_overridable :: setStatus
procedure :: unsetStatus
!
procedure( cleanup ), deferred :: cleanup
!procedure, nopass :: do_nothing
end type A
!
interface cleanup
!
subroutine cleanup(this)
import A
class(A), intent(in out) :: this
end subroutine cleanup
end interface cleanup
!
contains
!
subroutine setStatus(this)
class(A), intent(in out) :: this
!
this%status = .true.
end subroutine setStatus
!
subroutine unsetStatus(this)
class(A), intent(in out) :: this
!
this%status = .false.
end subroutine unsetStatus
! !
! subroutine do_nothing()
! end subroutine do_nothing
!
end module A_Mod
cat B_Mod.f90
!
module B_Mod
!
use A_Mod
implicit none
!
private
integer, private, parameter :: version = 0
!
type, public, abstract, extends(A) :: B
integer :: action
contains
!
procedure (free_resources), deferred :: free_resources
procedure (reset), deferred :: reset
procedure (setup), deferred :: setup
!
procedure, non_overridable :: init
!
! Procedures from A
procedure, non_overridable :: finalize
procedure, non_overridable :: cleanup
!
end type B
!
interface
!
subroutine free_resources( this )
import B
class(B), intent(in out) :: this
!
end subroutine free_resources
!
subroutine reset( this )
import B
class( B ), intent(in out) :: this
end subroutine reset
!
subroutine setup( this )
import B
class(B), intent(in out) :: this
!
end subroutine setup
!
end interface
!
contains
!
subroutine init( this )
class(B), intent(in out) :: this
!
write(*,"(' B::init, calling setup')")
call this%setup()
write(*,"(' B::init done ...............')")
this%action=1
!
end subroutine init
!
subroutine finalize( this )
class(B), intent(in out) :: this
!
write(*,"(' B::finalize, calling free_resources')")
call this%free_resources( )
write(*,"(' B::finalize, calling cleanup')")
call this%cleanup()
write(*,"(' B::finalize done ...................')")
this%action=0
!
end subroutine finalize
!
subroutine cleanup( this )
class(B), intent(in out) :: this
!
!call this%do_nothing()
write(*,"(' B::cleanup')")
!call this%reset()
this%action=-1
!
end subroutine cleanup
!
end module B_Mod
$ cat C_Mod.f90
!
module C_Mod
!
use B_Mod
!
implicit none
!
private
!
type, public, extends(B) :: C
!integer :: n
contains
! From B
procedure :: free_resources
procedure :: reset
procedure :: setup
!
end type C
!
contains
!
subroutine setup( this )
class(C), intent(in out) :: this
!
!call this%do_nothing()
write(*,"(' C::setup')")
!
end subroutine setup
!
subroutine free_resources( this )
class(C), intent(in out) :: this
!
!call this%do_nothing()
write(*,"(' C::free_resources')")
!
end subroutine free_resources
!
subroutine reset(this)
class(C), intent(in out) :: this
!
!call this%do_nothing()
write(*,"(' C::reset')")
!
end subroutine reset
!
end module C_Mod
$ cat test.f90
!> @file test.f90
!! to test the basic functionalities of the framework
!<
!> @brief test program
!!
!<
program test
use C_Mod
implicit none
!
!
call test_grid1d()
!
contains
!
subroutine test_grid1d()
type(C) :: c1
!
write(*,"('Test: calling C%init')")
call c1%init()
write(*,"('Test: calling C%finalize')")
call c1%finalize()
write(*,"('Test:done.......................')")
!
end subroutine test_grid1d
!
end program test
编译并运行为
COMPILE=gfortran -g
LINK=gfortran
${COMPILE} A_Mod.f90 -o A_Mod.o
${COMPILE} B_Mod.f90 -o B_Mod.o
${COMPILE} C_Mod.f90 -o C_Mod.o
${COMPILE} test.f90 -o test.o
${LINK} -o test A_Mod.o B_Mod.o C_Mod.o test.o
./test
这在当前gfortran(9.3)中似乎bug。它需要非常特殊的情况,包括将模块的源代码放在单独的文件中。
如果你想解决这个错误,最好通过正常的gcc错误报告渠道(https://gcc.gnu.org/bugzilla/)进行报告。