! { dg-do compile } ! ! Tests the fix for PR61819. ! ! Contributed by Salvatore Filippone ! module foo_base_mod integer, parameter :: foo_ipk_ = kind(1) integer, parameter :: foo_dpk_ = kind(1.d0) type foo_d_base_vect_type real(foo_dpk_), allocatable :: v(:) contains procedure :: free => d_base_free procedure :: get_vect => d_base_get_vect procedure :: allocate => d_base_allocate end type foo_d_base_vect_type type foo_d_vect_type class(foo_d_base_vect_type), allocatable :: v contains procedure :: free => d_vect_free procedure :: get_vect => d_vect_get_vect end type foo_d_vect_type type foo_desc_type integer(foo_ipk_) :: nl=-1 end type foo_desc_type contains subroutine foo_init(ictxt) integer :: ictxt end subroutine foo_init subroutine foo_exit(ictxt) integer :: ictxt end subroutine foo_exit subroutine foo_info(ictxt,iam,np) integer(foo_ipk_) :: ictxt,iam,np iam = 0 np = 1 end subroutine foo_info subroutine foo_cdall(ictxt,map,info,nl) integer(foo_ipk_) :: ictxt, info type(foo_desc_type) :: map integer(foo_ipk_), optional :: nl if (present(nl)) then map%nl = nl else map%nl = 1 end if end subroutine foo_cdall subroutine foo_cdasb(map,info) integer(foo_ipk_) :: info type(foo_desc_type) :: map if (map%nl < 0) map%nl=1 end subroutine foo_cdasb subroutine d_base_allocate(this,n) class(foo_d_base_vect_type), intent(out) :: this allocate(this%v(max(1,n))) end subroutine d_base_allocate subroutine d_base_free(this) class(foo_d_base_vect_type), intent(inout) :: this if (allocated(this%v)) & & deallocate(this%v) end subroutine d_base_free function d_base_get_vect(this) result(res) class(foo_d_base_vect_type), intent(inout) :: this real(foo_dpk_), allocatable :: res(:) if (allocated(this%v)) then res = this%v else allocate(res(1)) end if end function d_base_get_vect subroutine d_vect_free(this) class(foo_d_vect_type) :: this if (allocated(this%v)) then call this%v%free() deallocate(this%v) end if end subroutine d_vect_free function d_vect_get_vect(this) result(res) class(foo_d_vect_type) :: this real(foo_dpk_), allocatable :: res(:) if (allocated(this%v)) then res = this%v%get_vect() else allocate(res(1)) end if end function d_vect_get_vect subroutine foo_geall(v,map,info) type(foo_d_vect_type), intent(out) :: v type(foo_Desc_type) :: map integer(foo_ipk_) :: info allocate(foo_d_base_vect_type :: v%v,stat=info) if (info == 0) call v%v%allocate(map%nl) end subroutine foo_geall end module foo_base_mod module foo_scalar_field_mod use foo_base_mod implicit none type scalar_field type(foo_d_vect_type) :: f type(foo_desc_type), pointer :: map => null() contains procedure :: free end type integer(foo_ipk_), parameter :: nx=4,ny=nx, nz=nx type(foo_desc_type), allocatable, save, target :: map integer(foo_ipk_) ,save :: NumMy_xy_planes integer(foo_ipk_) ,parameter :: NumGlobalElements = nx*ny*nz integer(foo_ipk_) ,parameter :: NumGlobal_xy_planes = nz, Num_xy_points_per_plane = nx*ny contains subroutine initialize_map(ictxt,NumMyElements,info) integer(foo_ipk_) :: ictxt, NumMyElements, info info = 0 if (allocated(map)) deallocate(map,stat=info) if (info == 0) allocate(map,stat=info) if (info == 0) call foo_cdall(ictxt,map,info,nl=NumMyElements) if (info == 0) call foo_cdasb(map,info) end subroutine initialize_map function new_scalar_field(comm) result(this) type(scalar_field) :: this integer(foo_ipk_) ,intent(in) :: comm real(foo_dpk_) ,allocatable :: f_v(:) integer(foo_ipk_) :: i,j,k,NumMyElements, iam, np, info,ip integer(foo_ipk_), allocatable :: idxs(:) call foo_info(comm,iam,np) NumMy_xy_planes = NumGlobal_xy_planes/np NumMyElements = NumMy_xy_planes*Num_xy_points_per_plane if (.not. allocated(map)) call initialize_map(comm,NumMyElements,info) this%map => map call foo_geall(this%f,this%map,info) end function subroutine free(this) class(scalar_field), intent(inout) :: this integer(foo_ipk_) ::info write(0,*) 'Freeing scalar_this%f' call this%f%free() end subroutine free end module foo_scalar_field_mod module foo_vector_field_mod use foo_base_mod use foo_scalar_field_mod, only : scalar_field,new_scalar_field implicit none type vector_field type(scalar_field) :: u(1) contains procedure :: free end type contains function new_vector_field(comm_in) result(this) type(vector_field) :: this integer(foo_ipk_), intent(in) :: comm_in this%u = [new_scalar_field(comm_in)] ! Removing this line eliminates the memory leak end function subroutine free(this) class(vector_field), intent(inout) :: this integer :: i associate(vf=>this%u) do i=1, size(vf) write(0,*) 'Freeing vector_this%u(',i,')' call vf(i)%free() end do end associate end subroutine free end module foo_vector_field_mod program main use foo_base_mod use foo_vector_field_mod,only: vector_field,new_vector_field use foo_scalar_field_mod,only: map implicit none type(vector_field) :: u type(foo_d_vect_type) :: v real(foo_dpk_), allocatable :: av(:) integer(foo_ipk_) :: ictxt, iam, np, i,info call foo_init(ictxt) call foo_info(ictxt,iam,np) u = new_vector_field(ictxt) call u%free() do i=1,10 u = new_vector_field(ictxt) call u%free() end do call u%free() call foo_exit(ictxt) end program