Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
Welcome to the Intel Community. If you get an answer you like, please mark it as an Accepted Solution to help others. Thank you!
26733 Discussions

Finalization of deallocated objects during allocation by assigment

andreasskeidsvoll
448 Views

I don't know if Fortran is expected to behave this way, but when I compile and run the folllowing program,

module object_type_module

  implicit none

  type :: object_type
    logical :: variable = .true.
  contains
    final :: finalize_object
  end type object_type

  interface object_type
    procedure return_object
  end interface object_type

contains

  function return_object() result(object)

    implicit none

    type(object_type) :: object

    print *, 'Inside return_object:', object%variable
    object%variable = .true.

  end function return_object

  subroutine finalize_object(object)

    implicit none

    type(object_type) :: object

    print *, 'Inside finalize_object:', object%variable

  end subroutine finalize_object

end module object_type_module

program allocation_finalization

  implicit none

  call allocate_object_automatically()

contains

  subroutine allocate_object_automatically()

    use object_type_module, only : object_type
    implicit none

    type(object_type), allocatable :: object

    print *, 'Before automatic allocation.'
    object = object_type()
    print *, 'After automatic allocation.'

  end subroutine allocate_object_automatically

end program allocation_finalization

 on my Ubuntu 20.10 with ifort version 2021.1, the result is

 Before automatic allocation.
 Inside return_object: T
 Inside finalize_object: F
 Inside finalize_object: T
 After automatic allocation.
 Inside finalize_object: T

The results lead me to think that the deallocated object on the left-hand-side of object = object_type() gets finalized during the function call. This since finalization is done three times, with object%variable evaluating as false once (non-allocatable object%variable is deallocated because object is deallocated?).

The behavior seems to go against the description of the FINAL Statement in the Developer Guide and Reference , which includes the statement:

"If the variable of an intrinsic assignment is not an unallocated allocatable array when the statement is executed, the variable is finalized after the expression on the right-hand side (RHS) is evaluated and before the variable is defined."

0 Kudos
1 Solution
Devorah_H_Intel
Moderator
295 Views

Yes, reported cases were not fixed yet. I have added this report as well.

View solution in original post

9 Replies
Steve_Lionel
Black Belt Retired Employee
428 Views

I think what is happening instead is that the finalizer is being called twice for the type constructor (which calls your return_object function). I recently reported a similar bug (CMPLRIL0-33567) for a "normal" type constructor.  The first time the finalizer is called, it is passed uninitialized storage. The following modification to your program demonstrates this:

module object_type_module

  implicit none

  type :: object_type
    integer :: variable = 314159
  contains
    final :: finalize_object
  end type object_type

  interface object_type
    procedure return_object
  end interface object_type

contains

  function return_object() result(object)

    implicit none

    type(object_type) :: object

    print *, 'Inside return_object:', object%variable
    object%variable = 271828

  end function return_object

  subroutine finalize_object(object)

    implicit none

    type(object_type) :: object

    print *, 'Inside finalize_object:', object%variable

  end subroutine finalize_object

end module object_type_module

program allocation_finalization

  implicit none

  call allocate_object_automatically()

contains

  subroutine allocate_object_automatically()

    use object_type_module, only : object_type
    implicit none

    type(object_type), allocatable :: object

    print *, 'Before automatic allocation.'
    object = object_type()
    print *, 'After automatic allocation.'

  end subroutine allocate_object_automatically

end program allocation_finalization
 Before automatic allocation.
 Inside return_object:      314159
 Inside finalize_object:  1869762652
 Inside finalize_object:      271828
 After automatic allocation.
 Inside finalize_object:      271828
andreasskeidsvoll
411 Views

I don't have access to the Fortran standard, but was led to think that the left-hand-side should be be finalized during assignment by this StackOverflow answer , which quotes from page 282 in the Modern Fortran Explained book:

"When a finalizable object is about to cease to exist (for example, by being deallocated or from execution of a return statement), the final subroutine is invoked with the object as its actual argument. This also occurs when the object is passed to an intent out dummy argument, or is the variable on the left-hand side of an intrinsic assignment statement. In the latter case, the final subroutine is invoked after the expression on the right-hand side has been evaluated, but before it is assigned to the variable."

FortranFan
Honored Contributor II
401 Views

https://j3-fortran.org/doc/year/18/18-007r1.pdf can be considered a proxy for the standard document.

Per Section 7.5.6.3 "When finalization occurs" on page 80, paragraph 1 with the line starting at 17, the finalization is not indicated for an unallocated allocatable variable.  'Object' you show in the original post. is as an unallocated allocatable variable.

 

andreasskeidsvoll
351 Views

@FortranFan Ok, I agree that the standard is clear on this – unallocated allocatable objects should not be finalized. I suppose your example acts according to the standard (the LHS variable is not an unallocatable allocatable anymore, and should thus be finalized). I find it easier to imagine that our two examples behave similarly, and that the "check" for the allocation status of LHS has been overlooked before finalization, than the case where double finalization somehow occurs on the RHS only for allocatable objects.

Anyway, it seems like an extra incorrect finalization happens in the example I gave, regardless of whether it happens on the LHS or RHS. I submitted a support request to Intel, will update this thread if I get any response.

FortranFan
Honored Contributor II
323 Views

@andreasskeidsvoll ,

In case you're unaware, you may also want to keep in mind the Fortran Discourse site for general language discussions:

https://fortran-lang.discourse.group/

There is a thread on this site also on finalization in relation to GCC/gfortran compiler:

 

 

Devorah_H_Intel
Moderator
296 Views

Yes, reported cases were not fixed yet. I have added this report as well.

View solution in original post

FortranFan
Honored Contributor II
427 Views

Per my interpretation of the Fortran standard, Intel Fortran invocation of the finalizer for the 'object' on LHS - an unallocated allocatable variable - is not called for.  This leads to the 3 invocations you notice

I have submitted support requests with Intel Fortran team at the Intel Online Service Center (https://supporttickets.intel.com/servicecenter?lang=en-US) to look into this.  I did so recently and have also done so previously (a couple of times I think) but which appear to have gotten overlooked in all the shuffles with Intel toolsets.

If you have support, you may consider the same.

Steve_Lionel
Black Belt Retired Employee
424 Views

It's the RHS, not LHS, that is being incorrectly finalized.

FortranFan
Honored Contributor II
417 Views
@Steve_Lionel wrote:
It's the RHS, not LHS, that is being incorrectly finalized.

 

Looking at the disassembly (albeit my knowledge here is poorer than a novice) and my prior analysis using code variations, I felt otherwise.  Say with this change:

  subroutine allocate_object_automatically()

    use object_type_module, only : object_type
    implicit none

    type(object_type) :: object !<-- nonallocatable 

The program output changes to the following:

 Before automatic allocation.
 Inside return_object: 314159
 Inside finalize_object: 314159
 Inside finalize_object: 271828
 After automatic allocation.
 Inside finalize_object: 271828

Note the 3rd line in output: 'Inside finalize_object: 314159' instead of some arbitrary output based on of '1869762652' as you reported earlier.  Per disassembly and inference, this appears to me to correspond to the variable 'object' i.e., the LHS.  That is, with ALLOCATABLE attribute of 'object', the output is arbitrary likely due to its undefined state.  When the ALLOCATABLE attribute is removed for the 'object', it comes into existence using the default initialized value of the component 'variable' and the program output is consistently '314159'.

If it was RHS that was getting finalized twice, I don't think this will be the case.  But I'm open to be proven wrong.

 

 

 

Reply