Search code examples
arraysfortranpolymorphism

Fortran polymorphic array assignment for `PACK`: issues


I am trying to code a computationally efficient PACK operation over a polymorphic array and I am running on issues with gfortran 9.2.0:

  • The PACK operation has to work on a polymorphic array of a derived type quantity, and return a result on itself
  • For reasons I'm not explaining here, this array should not be reallocated
  • In general, there is overlap between the locations of the returned indices, and those of the original array: something like array(1:5) = array([2,4,6,8,10])

I'm having problems, as the only version of the assigment I've tried with gfortran is with a loop - all array-based version either produce compiler or runtime segfaults.

An example is reported in this program:

module m
   implicit none
   
   type, public :: t
      integer :: i = 0
      contains
      
      procedure, private, pass(this) :: t_assign => t_to_t
      generic :: assignment(=) => t_assign
   end type t
   
   type, public, extends(t) :: tt
      integer :: j = 0
      contains
      procedure, private, pass(this) :: t_assign => t_to_tt
   end type tt
   
   contains
   
   elemental subroutine t_to_t(this,that)
      class(t), intent(inout) :: this
      class(t), intent(in   ) :: that
      this%i = that%i
   end subroutine t_to_t
   
   elemental subroutine t_to_tt(this,that)
      class(tt), intent(inout) :: this
      class(t ), intent(in   ) :: that

      this%i = that%i
      select type (thatPtr=>that)
         type is (t)
            this%j = 0
         type is (tt)
            this%j = thatPtr%j
         class default
            ! Cannot stop here
            this%i = -1
            this%j = -1
      end select        
   end subroutine t_to_tt
      
end module m

program test_poly_pack
   use m
   implicit none
   
   integer, parameter :: n = 100
   integer :: i,j
   class(t), allocatable :: poly(:),otherPoly(:)
         
   allocate(t :: poly(n))
   allocate(t :: otherPoly(10))
   
   ! Assign dummy values
   forall(i=1:n) poly(i)%i = i
   
   ! Array assignment with indices => ICE segfault:
   ! internal compiler error: Segmentation fault
   otherPoly(1:10) = poly([10,20,30,40,50,60,70,80,90,100])
   
   ! Scalar assignment with loop -> OK
   do i=1,10
     otherPoly(i) = poly(10*i)
   end do
   
   ! Array assignment with PACK => Compiles OK, Segfault on runtime. GDB returns: 
   ! Thread 1 received signal SIGSEGV, Segmentation fault.
   ! 0x000000000040163d in m::t_to_t (this=..., that=...) at test_poly_pack.f90:31
   ! 31                this%i = that%i


   otherPoly(1:10) = pack(poly,mod([(j,j=1,100)],10)==0)

   do i=1,10
     print *, ' polymorphic(',i,')%i = ',otherPoly(i)%i
   end do   
   
end program test_poly_pack   

Am I doing anything wrong, and/or is this only a compiler bug or there is any best practices I should be following?


Solution

  • The crashes are compiler bugs. When the compiler says internal compiler error ... Please submit a full bug report, you really can trust it and you should act accordingly (and submit the bug report). The runtime crash is a compiler bug as well (wrong code).

    If you know the actual types at the time of the assignment, you can use type guards

       select type (p => poly)
         type is (t)
           select type(op => otherpoly)
             type is (t)
               op(1:10) = pack(p,mod([(j,j=1,100)],10)==0)
           end select
       end select
    

    If you need it to be polymorphic - you probably have to reallocate

    allocate(otherPoly(1:10),source = pack(poly,mod([(j,j=1,100)],10)==0))
    

    until the bugs you hopefully reported are fixed.