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

How to adapt to compiler's change wrt polymorphic assignment ?

franck_reinquin
759 Views

Hello all,

We have a problem with existing code that no longer compiles with a "new" version of the oneAPI Fortran. On our cluster, the upgrades are slow so what I mean by "old" is : ifort version 2021.3.0, and "newer" is ifort version 2021.9.0. But I guess that the latest versions show the same behaviour since they are now compliant with the Fortran standards.

Here is a simplified sample of our code :

module measurements_management

  ! Measurements types
  !-------------------
  type :: generic_measurement
  end type generic_measurement

  type, extends(generic_measurement) :: measurement_as_reals
    real     :: real_measurement
  end type measurement_as_reals

  type, extends(generic_measurement) :: measurement_as_integers
    integer  :: int_measurement
  end type measurement_as_integers


  ! Generic management of measurement arrays
  ! ----------------------------------------
  type measurements_buffer
    integer    :: nb_used = 0
    class(generic_measurement), allocatable, dimension(:) :: tab_measurements

  contains
    procedure   :: init    => buffer_init
    procedure   :: realloc => buffer_realloc
  end type measurements_buffer

contains

    ! create a buffer containing an array with a selected measurement type
    ! the measurement array has an initial dimension of 50 elements
    subroutine buffer_init(this, measurement)

      class(measurements_buffer), intent(inout) :: this
      class(generic_measurement) :: measurement

      allocate(this%tab_measurements(50), mold=measurement)
    end subroutine buffer_init

    ! for an existing buffer created for a specific measurement type,
    ! reallocate the measurements array, adding 100 empty elements and
    ! copying the existing elements
    subroutine buffer_realloc(this)

      class(measurements_buffer), intent(inout) :: this

      !.. Local variables ..
      integer  :: current_size
      class(generic_measurement), allocatable, dimension(:) :: tab_tmp
	  
      current_size = size(this%tab_measurements)
      write(*,*) 'current size=', current_size
      allocate(tab_tmp(current_size+100), source=this%tab_measurements(1))
      write(*,*) 'tab_tmp size after alloc = ',size(tab_tmp)
      tab_tmp(1:current_size) = this%tab_measurements(1:current_size)
      write(*,*) 'tab_tmp size after copy = ',size(tab_tmp)
      call move_alloc(tab_tmp, this%tab_measurements)
	  
    end subroutine buffer_realloc

end module measurements_management



! example with a buffer of integer measurements
program polymorphic_realloc
  use measurements_management
  implicit none
  type(measurements_buffer) :: buffer_of_integer_measurements
  type(measurement_as_integers) :: measurement_int
  
  call buffer_of_integer_measurements%init(measurement_int)
  call buffer_of_integer_measurements%realloc()
  
end program polymorphic_realloc

We have a generic buffer that on initialization is set to contain an array of a specific measurement type. In this oversimplified sample, there are two measurement types (integer and real). In our software, there are 26 different types.

The problem occurs at line 55. It used to compile and works very well with the old compiler :

 current size=          50
 tab_tmp size after alloc =          150
 tab_size after copy =          150

With the new compiler, we get the well-known :

error #8304: In an intrinsic assignment statement, variable shall not be a non-allocatable polymorphic.

Just to check, I have changed line 55 to :

      tab_tmp = this%tab_measurements

OK, it compiles fine  with both compilers but I get :

 current size=          50
 tab_tmp size after alloc =          150
 tab_tmp size after copy =           50

So the reallocation is lost.

Is it possible to adapt the code and keep the generic handling of the buffer reallocation ?

Or do we have to change realloc() to an abstract subroutine and implement a dedicated subroutine for our 26 measurement types ?

Thanks in advance,

Franck

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
739 Views

This seems to do what you want and isn't any less efficient than what you had.

      current_size = size(this%tab_measurements)
      write(*,*) 'current size=', current_size
      !allocate(tab_tmp(current_size+100), source=this%tab_measurements(1))
      !write(*,*) 'tab_tmp size after alloc = ',size(tab_tmp)
      !tab_tmp(1:current_size) = this%tab_measurements(1:current_size)
      tab_tmp = reshape(this%tab_measurements,[current_size+100],this%tab_measurements)
      write(*,*) 'tab_tmp size after copy = ',size(tab_tmp)
      call move_alloc(tab_tmp, this%tab_measurements)

View solution in original post

2 Replies
Steve_Lionel
Honored Contributor III
740 Views

This seems to do what you want and isn't any less efficient than what you had.

      current_size = size(this%tab_measurements)
      write(*,*) 'current size=', current_size
      !allocate(tab_tmp(current_size+100), source=this%tab_measurements(1))
      !write(*,*) 'tab_tmp size after alloc = ',size(tab_tmp)
      !tab_tmp(1:current_size) = this%tab_measurements(1:current_size)
      tab_tmp = reshape(this%tab_measurements,[current_size+100],this%tab_measurements)
      write(*,*) 'tab_tmp size after copy = ',size(tab_tmp)
      call move_alloc(tab_tmp, this%tab_measurements)
franck_reinquin
731 Views

Thanks Steve !  That does the trick. You once more deserve your black belt.

Phew, I am really relieved.

0 Kudos
Reply