Hi Paul,
Am 11.02.22 um 10:08 schrieb Paul Richard Thomas via Fortran:
Your "stupid questions" are not at all stupid. The finalization of
'variable' that occurs in your testcase demonstrates that the finalization
with my patch is occurring at the wrong time. I now see that NAG is correct
on this.
Please press on with the questions!
Jerry's suggestion to add lots of prints turned out to be really
enlightening with regard to observable behavior. I rewrote the
testcase again and placed the interesting stuff into a subroutine.
This way one can distinguish what actually happens during program
start, entering and leaving a subroutine.
I encountered the least surprises (= none) with NAG 7.0 here.
For reference this is the output:
At start of program : 0
Enter sub : 0
After 1st allocation: 0
After 2nd allocation: 0
Checking MyType% ind: 21
Checking MyType2%ind: 22
Deallocate MyType : 0
# Leave desctructor1: 1 21
* MyType deallocated: 1
(kept MyType2 for automatic deallocation on return from sub)
Leave sub : 1
# Leave desctructor1: 2 22
After sub : 2
To make it short: the destructor is called only when deallocation
occurs, either explicitly or automatically.
Intel 2021.5.0:
At start of program : 0
Enter sub : 0
# Leave desctructor1: 1 0
After 1st allocation: 1
# Leave desctructor1: 2 0
After 2nd allocation: 2
Checking MyType% ind: 21
Checking MyType2%ind: 22
Deallocate MyType : 2
# Leave desctructor1: 3 21
* MyType deallocated: 3
(kept MyType2 for automatic deallocation on return from sub)
Leave sub : 3
# Leave desctructor1: 4 21
# Leave desctructor1: 5 22
# Leave desctructor1: 6 22
After sub : 6
So after entering the subroutine, the destructor is called twice,
but for unknown reasons element ind, which I had expected to be
either default-initialized to -1, or explicitly to 21 or 22, is 0.
The places where this happens seem to be the assignments of
MyType and MyType2.
Furthermore, variable MyType is finalized on return from sub,
although it is already deallocated, and MyType2 appears to
get finalized twice automatically.
I have no idea how this can get justified...
Crayftn 12.0.2: in order to make the output easier to understand,
I chose to reset final_count twice. This will become clear soon.
# Leave desctructor1: 1, 20
At start of program : 1
+++ Resetting final_count for Cray Fortran : Version 12.0.2
# Leave desctructor1: 1, 21
# Leave desctructor1: 2, 22
Enter sub : 2
+++ Resetting final_count for Cray Fortran : Version 12.0.2
After 1st allocation: 0
After 2nd allocation: 0
Checking MyType% ind: -21
Checking MyType2%ind: 22
Deallocate MyType : 0
# Leave desctructor1: 1, -21
* MyType deallocated: 1
(kept MyType2 for automatic deallocation on return from sub)
Leave sub : 1
# Leave desctructor1: 2, 22
After sub : 2
So it appears that Cray is calling the destructor for each declaration
where a constructor is involved, or the like. Even if this is a
parameter declaration, like in the main. Resetting the counter for
the first time.
On entering sub, I see now two finalizations before the first print.
Resetting the counter for the second time.
But then the assignments do not invoke finalization, where Intel did.
So this part appears more like NAG, but...
... something is strange here: component ind is wrong after the
first assignment. Looks clearly like a really bad bug.
Explicit and automatic deallocation seems fine.
Nvidia 22.2:
At start of program : 0
Enter sub : 0
After 1st allocation: 0
After 2nd allocation: 0
Checking MyType% ind: 21
Checking MyType2%ind: 22
Deallocate MyType : 0
# Leave desctructor1: 1 21
* MyType deallocated: 1
(kept MyType2 for automatic deallocation on return from sub)
Leave sub : 1
# Leave desctructor1: 2 1590094384
# Leave desctructor1: 3 22
After sub : 3
OK, that is really odd. Although valgrind does not report
invalid accesses, there is something really fishy here.
I have not investigated further. Nvidia is out for now.
One of the lessons learned is that it might be hard to write a
portable testcase that works for all compilers that rightfully(?)
can claim to implement finalization correctly... And I have only
scratched the surface so far.
Paul: do you think you can enhance your much more comprehensive
testcase to ease debugging further?
Cheers,
Harald
module testmode
implicit none
type :: simple
integer :: ind = -1
contains
final :: destructor1
end type simple
integer :: final_count = 0
contains
subroutine destructor1(self)
type(simple), intent(inout) :: self
final_count = final_count + 1
print *, "# Leave desctructor1:", final_count, self% ind
self% ind = - self% ind
end subroutine destructor1
end module testmode
program test_final
use, intrinsic :: iso_fortran_env
use testmode
implicit none
type(simple), parameter :: ThyType_param = simple(20)
character(80) :: compiler
compiler = compiler_version ()
print *
print *, "At start of program :", final_count
call reset ()
print *
call sub ()
print *
print *, "After sub :", final_count
contains
subroutine sub ()
type(simple), parameter :: ThyType = simple(21)
type(simple) :: ThyType2 = simple(22)
type(simple), allocatable :: MyType, MyType2
print *, "Enter sub :", final_count
call reset ()
MyType = ThyType
print *, "After 1st allocation:", final_count
MyType2 = ThyType2
print *, "After 2nd allocation:", final_count
print *, "Checking MyType% ind:", MyType% ind
print *, "Checking MyType2%ind:", MyType2% ind
if (.not. allocated (MyType )) print *, "MyType?"
if (.not. allocated (MyType2)) print *, "MyType2?"
print *, "Deallocate MyType :", final_count
deallocate (MyType)
print *, "* MyType deallocated:", final_count
if (allocated (MyType2)) &
print *, "(kept MyType2 for automatic deallocation on return from sub)"
print *, "Leave sub :", final_count
end subroutine sub
!
subroutine reset ()
if (final_count == 0) return
if (compiler(1:4) == "Cray") then
print *, "+++ Resetting final_count for ", trim (compiler)
final_count = 0 ! reset for crayftn 12.0.2
end if
end subroutine reset
end program test_final