我构建了一个简单的案例来重现下面的问题。我无法进一步减少它。 问题描述: 我有3节课
- 模块 A_Mod (A_Mod.f90) 中的抽象类,具有延迟过程
cleanup
- B,扩展 A 的抽象类,位于模块 B_Mod (B_Mod.f90) 中。 B 实现延迟过程
cleanup
,定义并实现过程:init、finalize
,并定义以下延迟过程:setup、free_resources、reset
; - C,扩展 B,在模块 C_Mod (C_Mod.f90) 中并实现延迟过程
setup、free_resources、reset
定义变量(C 类型对象)的测试程序 (test.f90),调用 init
,然后调用该对象的 finalize
过程。
看起来源代码中调用的过程并不是可执行文件中调用(运行)的过程:子例程调用在编译时困惑。一个小更改(使用 gfortran 7.5.0),例如删除类 B
的过程 init
上的 non_overridable
会导致无限循环调用 init
(就像 init 和 setup 指向同一个过程一样)。可以通过代码中的一些其他小更改来重现此循环行为。
我怀疑问题与deferred
和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:
- ifort 19.0.5.281 => 预期结果
- ifort 19.0.4.243 => 预期结果
- ifort 19.0.2.187 => 预期结果
- ifort 18.0.1 => 预期结果
- ifort 17.0.4 => 预期结果
- GNU Fortran (GCC) 4.8.5 => 预期结果
- GNU Fortran (GCC) 6.3.0 => 错误结果(与其他有点不同,见下文)
- GNU Fortran (GCC) 7.5.0 => 错误结果
- GNU Fortran (GCC) 8.4.0 => 错误结果
- GNU Fortran (GCC) 9.2.0 => 错误结果
- GNU Fortran (GCC) 8.2.0 => 错误结果
- GNU Fortran (GCC) 7.3.0 => 错误结果
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) 中的一个错误。它需要非常具体的环境,包括将模块的源代码放在单独的文件中。
如果您希望解决该错误,最好通过正常的 gcc 错误报告 channel ( https://gcc.gnu.org/bugzilla/ ) 进行报告。
关于oop - 使用延迟和不可重写过程和 gcc 编译器面向对象的 Fortran 中的不确定行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61280540/