Oop Fortran面向对象中的不确定性行为,带有延迟和不可重写过程以及gcc编译器
我构建了一个简单的案例来重现下面的问题。我不能再减少了。 问题描述: 我有三节课Oop Fortran面向对象中的不确定性行为,带有延迟和不可重写过程以及gcc编译器,oop,fortran,abstract-class,gfortran,Oop,Fortran,Abstract Class,Gfortran,我构建了一个简单的案例来重现下面的问题。我不能再减少了。 问题描述: 我有三节课 A、 模块A_Mod(A_Mod.f90)中的抽象类,带有延迟过程cleanup B、 在模块B_Mod(B_Mod.f90)中扩展A的抽象类。B执行延迟过程清理,定义并执行以下过程:初始化、完成,并定义以下延迟过程:设置、释放资源、重置 C、 在模块C_Mod(C_Mod.f90)中扩展B,并执行延迟过程设置、释放资源、重置 定义变量(C型对象)的测试程序(test.f90),调用init,然后对对象执行fi
- A、 模块A_Mod(A_Mod.f90)中的抽象类,带有延迟过程
cleanup
- B、 在模块B_Mod(B_Mod.f90)中扩展A的抽象类。B执行延迟过程
,定义并执行以下过程:清理
,并定义以下延迟过程:初始化、完成
李>设置、释放资源、重置
- C、 在模块C_Mod(C_Mod.f90)中扩展B,并执行延迟过程
设置、释放资源、重置
init
,然后对对象执行finalize
过程
源代码中调用的过程似乎不是可执行文件中调用(运行)的过程:子例程调用在编译时出错。在类B
的过程init
上删除non_overridable
之类的小更改(使用gfortran 7.5.0)会产生一个无限循环调用init
(就像init和setup指向同一过程一样)。这种循环行为可以通过代码中的其他一些小更改来重现
我怀疑问题与延迟的
和不可重写的
有关。除非我犯了错误,否则它看起来像是4.8.5之后引入的gfortran中的一个bug
预期产出:
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=>错误结果
$ cat A_Mod.f90
这似乎是当前gfortran(9.3)中的一个错误。它需要非常具体的环境,包括在单独的文件中包含模块的源代码
如果你想解决这个bug,最好通过普通的gcc bug报告渠道()进行报告。我猜问题是“这是一个编译器bug吗”?@IanH,在我看来像是一个编译器bug!那么,你打算向开发人员报告这个bug吗?我刚刚报告:它是6.3.0版之后的bug,可能是之前的版本。4.8.5产生预期结果。
$ 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