Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28945 Discussions

About the forbidden deallocation of a polymorphic entity in a pure procedure.

FlyingHermes
New Contributor I
1,237 Views

Hi,

I've recently updated ifort from version 2021.8.0 to version 2021.9.0.
Some code which was previously compiling file now gives the following error:

error #5585: A statement that might result in the deallocation of a polymorphic entity is not permitted in a pure procedure.


Here is a small reproducer.

 

Module MyModule

implicit none

Type :: MyType
class(*) ,allocatable :: p
contains
procedure :: Free
End Type

contains

Pure Subroutine Free( This )
class(MyType) ,intent(inout) :: This
deallocate( This%p ) ! <====== Using ifort 2021.9.0: error #5585: A statement that might result in the deallocation of a polymorphic entity is not permitted in a pure procedure.
End Subroutine

End Module

Program Main

use MyModule

implicit none

type(MyType) :: var

allocate( var%p , source = 9 )
write(*,*) "allocated(var%p) = ", allocated(var%p)
write(*,*) "call var%Free"
call var%Free
write(*,*) "allocated(var%p) = ", allocated(var%p)

End Program

 

The following built instructions (I'm using the intel modulefiles)

 

echo "##########"
module purge --silent
module load compiler/2023.0.0 --silent
ifort -v
ifort main.f90
./a.out

echo "##########"
module purge --silent
module load compiler/2023.1.0 --silent
ifort -v
ifort main.f90
./a.out

 

give

 

##########
ifort version 2021.8.0
allocated(var%p) = T
call var%Free
allocated(var%p) = F
##########
ifort version 2021.9.0
main.f90(15): error #5585: A statement that might result in the deallocation of a polymorphic entity is not permitted in a pure procedure.
deallocate( This%p ) ! <====== Using ifort 2021.9.0: error #5585: A statement that might result in the deallocation of a polymorphic entity is not permitted in a pure procedure.
--^
compilation aborted for main.f90 (code 1)

 


Now, my fear is that this error is actually valid and it was simply not caught in ifort version 2021.8.0.
However, it puts a lot of restriction on the use of the pure attribute, which nearly becomes useless when polymorphic variables are involved.


Is this restriction really necessary ?

Is there any workaround apart from removing the pure attribute ?

 

Thank you.

 

0 Kudos
4 Replies
jdelia
New Contributor I
1,211 Views

Dear FlyingHermes,

Are you tried with gfortran?, e.g.

$  gfortran --version
GNU Fortran (GCC) 13.0.1 20230124 (experimental)

$ gfortran -march=native -mtune=native -fall-intrinsics -fcheck=all -fimplicit-none -fmax-errors=4 -std=f2018 -Wall -Waliasing -Warray-temporaries -Wcharacter-truncation -Werror -Wextra -Wimplicit-interface -Wimplicit-procedure -Wintrinsic-shadow -Wline-truncation -Wrealloc-lhs-all -Wsurprising -Wtabs -Wunused-parameter -O2 -c test180.f90
test180.f90:29:22:

29 | pure subroutine free (this)
| 1
Error: ‘free’ declared at (1) may shadow the intrinsic of the same name. In order to call the intrinsic, explicit INTRINSIC declarations may be required. [-Werror=intrinsic-shadow]

Then, if the pure subroutine free is renamed, say, to pure subroutine free_b, then,

$ test180.exe
allocated(var%p) = T
call var%free
allocated(var%p) = F

However, it persists the restriction already shown, i.e.

$ ifort --version

/opt/intel/oneapi/compiler/2023.1.0/linux/bin/intel64/ifort

$ ifort -o test180-i.exe test180.f90
test180.f90(30): error #5585: A statement that might result in the deallocation of a polymorphic entity is not permitted in a pure procedure.
deallocate (this%p) ! <= using ifort 2021.9.0: error #5585:
----^
compilation aborted for test180.f90 (code 1)

 

Regards,

0 Kudos
IanH
Honored Contributor III
1,211 Views

It is a restriction arising from a required correction to F2008 as published.  There is no work around with the current language (that may change in future).

The Fortran concept of PURE imposes a set of checkable constraints on a procedure, that collectively guarantee that calls to the procedure will have reasonably deterministic semantics when it is invoked from code that has no ordering requirements (like DO CONCURRENT, specification parts, FORALL...). 

(Calls from code with no ordering requirement may permit a suitably capable Fortran processor to arrange the calls such that they happen at the same time, so people get excited about PURE and parallel code, but that's actually secondary to its language purpose.)

Final procedures for a derived type do not have to be PURE.  There is no practical way that a compiler can check whether final procedures for a derived type that is an extension of the type of a polymorphic argument are pure.  This inability to check breaks the Fortran language concept of PURE - hence the correction to the language.

In future revisions of the language (not sure where this is at with current language proposals) types could be augmented with an attribute that says "extensions must not have impure FINAL procedures", which would then be checkable, and those sorts of types would be permitted to be deallocated inside PURE procedures.  But today is not the future.

Meanwhile it is just certain contexts that are prohibited for polymorphic variables - "nearly useless" is a bit of an exaggeration. 

0 Kudos
FlyingHermes
New Contributor I
1,077 Views

Thank you.

What you say makes sense. In particular, that the language needs to introduce a set of constraints that guarantee that pure procedures can be called within loops without any ordering requirements. Since non-polymorphic procedure arguments can be deallocated inside pure procedures, I was wrongly assuming that it was also the true for polymorphic procedure arguments.

However, I still don't understand why there is a particular constraint for the deallocation of polymorphic arguments and not for non-polymorphic arguments. If someone out there has the answer I would be happy to know.

I hope this restriction will be relaxed in a future revision of the standards, if possible.

And regarding:


@IanH wrote:

Meanwhile it is just certain contexts that are prohibited for polymorphic variables - "nearly useless" is a bit of an exaggeration. 


You are right, it was not such a big deal after all. I always try to make all my procedures pure whenever possible, and, because of the transitive requirement of pure procedures, I was afraid that this restriction will force me to make many procedure impure. It was not the case.

0 Kudos
IanH
Honored Contributor III
1,063 Views

Consider your original module in combination (take out the Pure keyword if you want this all to compile) with this additonal module and alternative main program:

 

Module MyOtherModule
  Implicit None
  Type :: HasAFinalizer
  Contains
    Final ::f
  End Type HasAFinalizer
  
  Integer :: global
Contains
  Subroutine f( arg )
    Type(HasAFinalizer) :: arg
    ! Not pure things!
    global = 123
    Print "('I am not pure!!')"
  End Subroutine f
End Module MyOtherModule

Program Main
  use MyModule
  Use MyOtherModule
  implicit none

  type(MyType) :: var

  allocate( var%p , source = HasAFinalizer() )
  write(*,*) "allocated(var%p) = ", allocated(var%p)
  write(*,*) "call var%Free"
  call var%Free
  write(*,*) "allocated(var%p) = ", allocated(var%p)
End Program

 

When compiling the subroutine that was supposed to be pure, the compiler has no idea what the type of This%p is.  It has no idea whether This%p has a finalizer, if it did have a finalizer, it has no idea whether it is pure or not.  Without knowing, this the compiler cannot check whether the subroutine is pure.

For non-polymorphic arguments the compiler knows everything about the type and its bindings - so it can check purity.

Reply