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

Extended type objects not working properly with Intel Fortran 18

clang001
Beginner
627 Views

We have a large code base that works well with Intel 17.x and gfortran.  I recently upgraded to Intel 18 and all tests are now broken.  For some reason, methods on a polymorphic object are not not being called properly.  Instead of calling the method for an extended type, the program is calling the method for the parent type.  It would be some work to make a small example, so at this point and am trying to see if this bug has been detected.

0 Kudos
8 Replies
FortranFan
Honored Contributor II
627 Views

@clang001,

A regression is always plausible (see threads such as https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/752348#new) but then there is also the possibility your extended types are relying on erroneous implementations of features introduced in Fortran starting with the 2003 standard which might have since been corrected in the compiler(s) to make them conform to the standard.

Good luck but note the chances are you will need a complete reproducer to get to the bottom of the problem.

0 Kudos
clang001
Beginner
627 Views

I seem to have found the issue.  I think it is a bug in Intel Fortran 18, thought I can't be sure.  The following code is what I was using in a parent class (derived type with type-bound procedures).  I also had child classes (extended types) that overrode the read_int_array and read_dbl_array procedures.  They also had private tags.   And this code has worked fine for a long time and with a variety of compilers.  Well it turns out the private tags were causing the problem with Intel Fortran 18.  With the private tags, the procedures were not overridden, and instead the parent class procedures were executed.  It could be that I was doing it wrong before, but it seems like a bug to me.  Thought I would post in case someone else runs into this.

 

Code that does not work on Intel Fortran 18:

    procedure, private :: read_int_array
    procedure, private :: read_dbl_array
    generic, public    :: read_grid_array => read_int_array, read_dbl_array
Fix is to remove private tags in parent and child classes

    procedure          :: read_int_array
    procedure          :: read_dbl_array
    generic, public    :: read_grid_array => read_int_array, read_dbl_array

 

0 Kudos
Steve_Lionel
Honored Contributor III
627 Views

We'd need to see a buildable example to be sure, and please report this to the Intel Online Service Center.

0 Kudos
IanH
Honored Contributor II
627 Views

Are the parent and child types defined within the same module?  If they are in different modules, the child types cannot override the private bindings of the parent.

0 Kudos
reinhold-bader
New Contributor II
627 Views

The most likely explanation is that you have run afoul of a change to the Fortran 2003 semantics that was introduced as a corrigendum to the standard. It significantly changed the behaviour of PRIVATE type-bound procedures. In effect, it prevents overriding a type-bound procedure outside the module that declares the type and its type-bound procedure.

An attempt to do this effectively only adds a new type-bound procedure to the new type that can only be invoked if the declared type of the object is the extension type.

Intel Fortran implemented this corrigendum to the standard with the 18.0 release. At some point I heard that a compiler option may exist to revert to the old (now non-conforming) behaviour but I wasn't able to find it.

Cheers

Reinhold

0 Kudos
clang001
Beginner
627 Views

Thank you people.  That makes sense.  The parent and child types are in different modules.  I can see why the PRIVATE attribute can cause problems.  Glad I was able to isolate it without too much trouble, and fortunately we didn't use that pattern throughout our code.  Thanks again! 

0 Kudos
clang001
Beginner
627 Views

So I went ahead and mocked something up to demonstrate this issue, and it does look like there is something wrong.  The program below produces:

parent meth1; parent meth2; parent meth1; parent meth2

which suggests that something is not right with the method overloading.  Clearly the second two print statements should read child meth1 and child meth2. 

When the private attributes are removed for both the parent and child procedures then the statements read ;

parent meth1; parent meth2; child meth1; child meth2

Hopefully I haven't done something obviously wrong here.

module ParentModule
  implicit none
  type ParentType
  contains
    procedure, private :: meth1
    procedure, private :: meth2
    generic, public :: meth => meth1, meth2
  end type ParentType
  contains
  subroutine meth1(this, i)
    class(ParentType) :: this
    integer, intent(in) :: i
    print *, 'parent meth1'
  end subroutine meth1
  subroutine meth2(this, d)
    class(ParentType) :: this
    double precision, intent(in) :: d
    print *, 'parent meth2'
  end subroutine meth2
end module ParentModule
  
module ChildModule
  use ParentModule, only: ParentType
  implicit none
  type, extends(ParentType) :: ChildType
  contains
    procedure, private :: meth1
    procedure, private :: meth2  
  end type ChildType
  contains
  subroutine meth1(this, i)
    class(ChildType) :: this
    integer, intent(in) :: i
    print *, 'child meth1'
  end subroutine meth1
  subroutine meth2(this, d)
    class(ChildType) :: this
    double precision, intent(in) :: d
    print *, 'child meth2'
  end subroutine meth2
end module ChildModule
  
program test
  use ParentModule, only: ParentType
  use ChildModule, only: ChildType
  implicit none
  type(ParentType) :: p
  type(ChildType) :: c
  call p%meth(1)
  call p%meth(1.d0)
  call c%meth(1)
  call c%meth(1.d0)
  print*, 'done'
end

 

0 Kudos
IanH
Honored Contributor II
627 Views

Things are working as expected.

The main program calls the generic binding `meth`, which is defined in the parent type, with specific bindings that are also in the parent type.  Those specific bindings are not overridden - the bindings of the same name in the child type are a separate pair, because the child type is being defined in a separate module and the original bindings in the parent type are private as discussed above.  Call the generic - get the specific bindings as defined in the parent type.

 

0 Kudos
Reply