我构建了一个简单的案例来重现下面的问题。我无法进一步减少它。问题描述:我有3个课程
cleanup
的模块A_Mod(A_Mod.f90)中的抽象类>cleanup
,定义并实现了过程init, finalize
,并定义了以下延迟的过程:setup, free_resources, reset
;setup, free_resources, reset
定义变量(类型为C的对象)的测试程序(test.f90),在对象上调用init
,然后调用finalize
过程。
似乎源代码中调用的过程不是可执行文件中正在调用的过程:子例程调用在编译时被弄乱了。进行较小的更改(使用gfortran 7.5.0),例如删除类non_overridable
的过程init
上的B
,将导致不确定的循环调用init
(就像init和setup指向同一过程一样)。此循环行为可以通过代码中的其他一些小更改来重现。
我怀疑问题与deferred
和non_overridable
有关。除非我犯错,否则它看起来像gfortran中的错误,该错误是在4.8.5之后引入的。
预期输出:
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
我构建了一个简单的案例来重现下面的问题。我无法进一步减少它。问题描述:我有3个类A,模块A_Mod(A_Mod.f90)中的抽象类,带有延迟的...
这似乎是当前gfortran(9.3)中的错误。这需要非常特殊的环境,包括将模块的源文件放在单独的文件中。