Bug 64290

Summary: [F03] No finalization at deallocation of LHS
Product: gcc Reporter: Bálint Aradi <baradi09>
Component: fortranAssignee: Paul Thomas <pault>
Status: ASSIGNED ---    
Severity: normal CC: drikosev, janus, pault
Priority: P3 Keywords: wrong-code
Version: 5.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2014-12-15 00:00:00
Bug Depends on:    
Bug Blocks: 37336    
Attachments: Self contained source demonstrating
Initial fix for the PR
Slightly better patch

Description Bálint Aradi 2014-12-12 16:25:53 UTC
Created attachment 34268 [details]
Self contained source demonstrating

During an assingment with an allocatable type on both, the LHS and the RHS, the destructor of the LHS-type is not called. IMHO, this is erroneous behaviour as the LHS gets (hopfully) deallocated on the assignment.
Comment 1 janus 2014-12-15 11:46:48 UTC
Confirmed. See also PR 37336 comment 27.
Comment 2 Paul Thomas 2021-01-11 08:17:11 UTC
Created attachment 49936 [details]
Initial fix for the PR

Triggered by a recent thread on clf, I have made a first stab at this PR. This patch is thus far perfect and has the following regressions:

FAIL: gfortran.dg/class_optional_1.f90   -O0  execution test
FAIL: gfortran.dg/dynamic_dispatch_6.f03   -O1  execution test
FAIL: gfortran.dg/finalize_15.f90   -O0  (internal compiler error)
FAIL: gfortran.dg/finalize_25.f90   -O0  execution test
FAIL: gfortran.dg/finalize_29.f08   -O0  execution test
FAIL: gfortran.dg/prof/dynamic_dispatch_6.f03 execution,    -fprofile-generate -D_PROFILE_GENERATE

which is not too bad for a first attempt. Note that for arrays, finalization is occurring before reallocation of the lhs contrary to the requirements of the standard.

This test, based on the reporter's testcase, works as intended:
module testmode
  implicit none

  type :: simple
    integer :: ind
    final :: destruct1, destruct2
  end type simple

  integer :: check_scalar
  integer :: check_array(2)
  integer :: final_count = 0


  subroutine destruct1(self)
    type(simple), intent(inout) :: self

!    print *, "DESTRUCTING SCALAR", self%ind
    check_scalar = self%ind
    check_array = 0
    final_count = final_count + 1

  end subroutine destruct1

  subroutine destruct2(self)
    type(simple), intent(inout) :: self(:)

!    print *, "DESTRUCTING ARRAY", self%ind
    check_scalar = 0
    check_array = self%ind
    final_count = final_count + 1

  end subroutine destruct2

  subroutine test (cnt, scalar, array, off)
    integer :: cnt
    integer :: scalar
    integer :: array(:)
    integer :: off
    if (final_count .ne. cnt) stop 1 + off
    if (check_scalar .ne. scalar) stop 2 + off
    if (any (check_array .ne. array)) stop 3 + off
  end subroutine test

end module testmode

program test_final
  use testmode
  implicit none

  type(simple), allocatable :: myres, myres2
  type(simple), allocatable :: myarray(:)
  type(simple) :: thyres = simple(21), thyres2 = simple(22)

  myres%ind = 1
  myres2%ind = 2
  myres = myres2
  call test(1, 1, [0,0], 10)

  myarray%ind = [42, 43]
  myarray = [thyres, thyres2]
  call test(2, 0, [42,43], 20)

  thyres2 = simple(99)
  call test(3, 22, [0,0], 30)

  thyres = thyres2
  call test(4, 21, [0,0], 40)

  deallocate (myres, myres2)
  call test(6, 2, [0,0], 100)

  deallocate (myarray)
  call test(7, 0, [21,22], 200)

end program test_final

Comment 3 Paul Thomas 2021-01-12 12:04:46 UTC
Created attachment 49952 [details]
Slightly better patch

This gets rid of the regression in gfortran.dg/finalize_29.f08.

However, finalize_25.f90 exposes the real scale of the problem because it shows that finalization is partially implemented for variables with allocatable components and this causes collisions with the finalization in the patch.


Comment 4 Ev Drikos 2021-01-12 13:03:38 UTC


There are some open PRs related to elemental finalisers. Having seen
how you reallocate arrays, I'd the impression that the functionality
for polymorphic entities would had a similar design. As one may also
need ie to reset at least the '_len' field, ie class(*) x; x='a';

Which in turn may not cause regressions to "finalize_25.f90" and I see
that this test counts some finalisation calls. Of course I don't doubt
that finalization may be partially implemented as you say. Admittedly
the interpretation of & seems to be a herculean task.

To my understanding, an outcome of the discussion in c.l.f is that the
reallocation takes place if the LHS & RHS have different runtime types,
at least this seems to be a criterion for no rank polymorphic entities.

Hope this helps,
Ev. Drikos
Comment 5 Ev Drikos 2021-01-18 08:32:17 UTC
Created attachment 49990 [details]


Having seen a Note in F2018 draft, specifically Interpretation of intrinsic assignments,
I wrote a test case that I thought should be ok,
but I face this: 

$ gfortran8 realloc_class_8.f95 && ./a.out


 NAME=NONE [LEN=           4 ]
 USER=NONE [LEN=           4 ]

 NAME=Mr. John Richard Doe [LEN=          20 ]
 USER=Mr. John RichardMr.  [LEN=          20 ]

Of course, there are no finalizers in this case,
yet I think that is closely related because they
have the same bug fix (class reallocations).  

Hope this helps,
Ev. Drikos