Description
@certik asked that I share this here.
I've encountered an issue with finalization that is illustrated by the example that follows. There is a parent type and child type that extends the parent, each with a final subroutine. The child type has two derived type components, one allocatable, the other not. The component types also have final subroutines. The point of the example is to reveal the order in which the final subroutines are called.
Two compilers produce the results I expected, namely the string "CABP" for Child, component A, component B, and Parent. "CBAP" would have been equally acceptable. A third compiler produces the string "CBPA". The preliminary response from the vendor of the latter compiler is that the standard is ambiguous with conflicting requirements and that choice of behavior is arguably valid. They did go into some explanation, but I haven't yet understood their argument. I'll be following up with them, and as I understand more I'll comment here with it. Section 7.5.6.2 (2018) seems pretty clear to me (arguing for "CABP") but there may well be other parts of the standard that are inconsistent with it -- I have a lot of respect for this vendor. If an official interpretation and standard clarification is required I would strongly urge for "CABP".
[Edit] The core question here is why does the third compiler vendor believe the allocatable component A have to be finalized last after the parent, whereas the non-allocatable component B should be finalized before the parent.
Here is the example
module child_type
implicit none
private
type :: objectA
contains
final :: finalize_objectA
end type
type :: objectB
contains
final :: finalize_objectB
end type
type :: parent
contains
final :: finalize_parent
end type
type, extends(parent), public :: child
type(objectA), allocatable :: A
type(objectB) :: B
contains
procedure :: init
final :: finalize_child
end type
contains
subroutine finalize_objectA(this)
type(objectA), intent(inout) :: this
write(*,'("A")',advance='no')
end subroutine
subroutine finalize_objectB(this)
type(objectB), intent(inout) :: this
write(*,'("B")',advance='no')
end subroutine
subroutine finalize_parent(this)
type(parent), intent(inout) :: this
write(*,'("P")',advance='no')
end subroutine
subroutine finalize_child(this)
type(child), intent(inout) :: this
write(*,'("C")',advance='no')
end subroutine
subroutine init(this)
class(child), intent(inout) :: this
allocate(this%A)
end subroutine
end module
program main
use child_type
call run
contains
subroutine run
type(child) :: c
call c%init
end subroutine
end program