【发布时间】:2020-04-17 20:57:32
【问题描述】:
我构建了一个简单的案例来重现下面的问题。我无法进一步减少它。 问题描述: 我有 3 节课
- A,模块 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
【问题讨论】:
-
我认为问题是“这是一个编译器错误”吗?
-
@IanH,在我看来就像一个编译器错误!
-
那么,你要向开发者报告这个错误吗?
标签: oop fortran abstract-class gfortran