1

The following test program attempts to perform something similar to Fortran's pack intrinsics with a polymorphic derived type. In this example, the odd elements (1,3,5,7,9) of the 10-sized array are packed to positions (1:5). All assignments work besides the 1st element:

module assign
        implicit none
        private


        type, public :: t
             integer :: a              
             contains
                   procedure :: destroy=>t_destroy
                   procedure :: assign=>t_assign
                   generic :: assignment(=) =>assign 
        end type t

   contains


   elemental subroutine t_destroy(this)
        class(t), intent(inout) :: this
        this%a = 0
   end subroutine t_destroy

   subroutine t_assign(this,that)
        class(t), intent(inout) :: this
        class(t), intent(in) :: that

        call this%destroy() ! Clean memory first

        select type (thatPtr=>that)
           type is (t)
               this%a = thatPtr%a    
        end select

   end subroutine t_assign
end module assign

program test
        use assign
        type(t), allocatable :: t1(:)

        allocate(t1(10))
        
        do i=1,10
          t1(i)%a = i
        end do  
        
        n = 0
        do i=1,10
          if (mod(i,2)/=0) then 
              n = n + 1
              t1(n) = t1(i)
              print *, 'i=',i,' t(i)%a=',t1(i)%a,' expected t(i)%a=',i,': ',merge('ERROR!','OK    ',t1(i)%a/=i)
          endif
        end do

end program test        

as the results are (note the first line):

 i=           1  t(i)%a=           0  expected t(i)%a=           1 : ERROR!
 i=           3  t(i)%a=           3  expected t(i)%a=           3 : OK
 i=           5  t(i)%a=           5  expected t(i)%a=           5 : OK
 i=           7  t(i)%a=           7  expected t(i)%a=           7 : OK
 i=           9  t(i)%a=           9  expected t(i)%a=           9 : OK

My understanding is that, when running t(1) = t(1), the underlying code is call t_assign(t(1),t(1)), which contains a call this%destroy(), so t(1) is deleted before copying. I'm not confortable with this:

  • Is this standard conforming behavior, or is the compiler (gfortran 10.2.0) just not catching the issue?
  • It's my understanding that an assignment in Fortran with the equal sign would always create a temporary variable, is this not the case with the overloaded subroutines?

Thanks, Federico

Federico Perini
  • 1,414
  • 8
  • 13
  • 1
    `t(1)=t(1)` is not the same as `call t_assign(t(1),t(1))` but `call t_assign(t(1),(t(1)))`. With that difference, does the result follow? – francescalus Jun 01 '21 at 13:34
  • well, the code just reads `t1(n) = t1(i)`, which on the first iterate, has `n==i==1` – Federico Perini Jun 01 '21 at 13:35
  • btw: YES! if I replace `t(n)=t(i)` with `call t1(n)%assign((t1(i)))`, everything works. So looks like a compiler issue? – Federico Perini Jun 01 '21 at 13:44
  • I think this is a duplicate of the linked question, but it's a _weak_ duplicate. The underlying behaviour of what _should_ happen by the standard is the same (ie., there is no aliasing), but your compiler appears to be doing it _with_ aliasing. (A bug was reported to GCC about the case of that linked question, so it's worth exploring whether that covers this case, another bug does, or whether a new bug should be opened.) – francescalus Jun 01 '21 at 13:57
  • 1
    The relevant bug is https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59202 – Vladimir F Героям слава Jun 01 '21 at 15:39

0 Answers0