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

Undefined intrinsic function PACK working on unlimited polymorphic allocatable arrays

xsl
Beginner
697 Views

The intrinsic function PACK is undefined when working on unlimited polymorphic allocatable arrays with ifort (IFORT) 18.0.1 20171018.

Can anybody explain whether this is an undefined behavior in Fortran language or it is a bug in the compiler?

The following code does not return a result as expected:

Program main

  integer :: a(4) = (/0, 1, 2, 3/)
  logical :: b(4) = (/.True., .True., .False., .False./)
  class(*), allocatable :: c(:)

  call array_pack(arrIn=a, arrOut=c, logic=b)

  select type(c)
  type is(integer)
     print*, 'c: ', c
  type is(real)
     print*, 'c: ', c
  end select

contains

  subroutine array_pack(arrIn, arrOut, logic)

    class(*), intent(inout) :: arrIn(:)
    class(*), intent(out), allocatable, target :: arrOut(:)
    logical, intent(in) :: logic(:)
    ! class(*), pointer :: arrOutLocal(:) => null()

    allocate(arrOut, source=arrIn)

    select type(arrOut)
    type is(integer)
       print*, 'arrOut: ', arrOut
    end select
    print*, logic
    arrOut = pack(arrIn, logic)
    select type(arrOut)
    type is(integer)
       print*, 'arrOut: ', arrOut
    end select

    print*, 'pack((/0, 1, 2, 3/), (/.True., .True., .False., .False./))', pack((/0, 1, 2, 3/), (/.True., .True., .False., .False./))

  end subroutine array_pack

end Program main

The expected result would be: 2, 3. as given by the last print line in the subroutine. However, with ifort 18, it fails to execute the second select type statement which indicates that the type of the array arrOut is unknown after the execution of PACK function. With gfortran-7, it still considers arrOut as an integer array but it also failed to give the expected result. What it prints is the original arrIn value, i.e., 0, 1, 2, 3, which indicates it failed in executing the PACK function.

0 Kudos
8 Replies
Juergen_R_R
Valued Contributor I
697 Views
You mean, the expected result should be 0, 1, and not 2,3 i guess. Indeed, nagfor gives me exactly that result. gfortran 8.0.1 (and probably also 7) stumble over the intrinsic assignment in

arrOut = pack(arrIn, logic)

where the result of pack(arrIn, logic) yields a an array of dimension 2, so the (originally size 4) arrOut needs to be reallocated from size 4 to size 2. As its type is unlimited polymorphic, that seems to be problematic for the compiler. If I compile gfortran 8.0.1 with -fcheck=all it throws a runtime error 

Fortran runtime error: Incorrect extent in return value of PACK intrinsic; is 2, should be 4


So, apparently the reallocation has not worked correctly. AFAIC tell the code seems standard conformant, but maybe Steve could have a closer look on it. It looks like a compiler bug for me both of ifort and gfortran, probably both connected with (re)allocate-on-assigment for unlimited polymorphism. 

 

0 Kudos
Juergen_R_R
Valued Contributor I
697 Views

Sorry, the code environment is scrambled, here is the ameliorated text:

You mean, the expected result should be 0, 1, and not 2,3 i guess. Indeed, nagfor gives me exactly that result. gfortran 8.0.1 (and probably also 7) stumble over the intrinsic assignment in
arrOut = pack(arrIn, logic)

where the result of pack(arrIn, logic) yields a an array of dimension 2, so the (originally size 4) arrOut needs to be reallocated from size 4 to size 2. As its type is unlimited polymorphic, that seems to be problematic for the compiler. If I compile gfortran 8.0.1 with -fcheck=all it throws a runtime error 
Fortran runtime error: Incorrect extent in return value of PACK intrinsic; is 2, should be 4

So, apparently the reallocation has not worked correctly. AFAIC tell the code seems standard conformant, but maybe Steve could have a closer look on it. It looks like a compiler bug for me both of ifort and gfortran, probably both connected with (re)allocate-on-assigment for unlimited polymorphism. 

0 Kudos
FortranFan
Honored Contributor II
697 Views

@Lu, Xushan,

Per my understanding of the Fortran standard, your code is non-conforming but I couldn't locate any constraints with it so a compiler may not be required to diagnose the issue.

Fortran standard specification of PACK intrinsic says, "Argument ARRAY shall be an array of any type." but an unlimited polymorphic entity is one of no type and it is not considered identical to any type including another unlimited polymorphic entity.  Hence my interpretation an actual argument of unlimited polymorphic nature cannot be passed to this intrinsic.

 

0 Kudos
Juergen_R_R
Valued Contributor I
697 Views

The last example in 

https://software.intel.com/en-us/fortran-compiler-18.0-developer-guide-and-reference-examples-of-intrinsic-assignment-to-polymorphic-variables

explains the case of (re)allocate-on-assignment for unlimited polymorphism. 

0 Kudos
FortranFan
Honored Contributor II
697 Views

Also, given the generic PACK facility and the Fortran 2008 facility of intrinsic assignment to an allocatable polymorphic, you may consider this as an option:

program main

   integer :: a(4) = [ 0, 1, 2, 3 ]
   logical :: b(4) = [ .True., .True., .False., .False. ]
   class(*), allocatable :: c(:)

   c = pack( array=a, mask=b )

   print*, 'pack( [0, 1, 2, 3], [.True., .True., .False., .False.])', &
      pack([0, 1, 2, 3], [.True., .True., .False., .False.])

   select type ( c )
      type is ( integer )
         print *, 'c: ', c
      type is ( real )
         print *, 'c: ', c
   end select

end program main

Upon execution, you will find c = [0, 1] which is only as expected.

0 Kudos
xsl
Beginner
697 Views

Thank you guys for all your quick comments! @FortranFan @Juergen R. 

I think I realized what went wrong in the code, and now both gfortran-7 and ifort give the expected results.

The problem is here:
allocate(arrOut, source=arrIn)

Like Juergen R. has pointed out, this does not allocate the array with the right length and this is the reason why ifort and gfortran not giving the expected results. They should all be able to detect the problem with array bounds checking flags turned on but I didn't use any of them, I just used the default flags. After changing the code to

allocate(arrOut(count(logic)), source=arrIn)

the compilers gave the correct results. So, I guess I shouldn't blame the compilers and also the thing that I tried in the toy code is possible with modern Fortran. My goal is to have some subroutine which takes care of this packing process regardless of the array data types. Without this data polymorphism, I need to write numerous codes for different types of data, intrinsic or user-defined. Luckily this seems to be possible now.

 

Best regards,

Xushan

0 Kudos
FortranFan
Honored Contributor II
697 Views

Lu, Xushan wrote:

.. My goal is to have some subroutine which takes care of this packing process regardless of the array data types. Without this data polymorphism, I need to write numerous codes for different types of data, intrinsic or user-defined.  ..

@Lu, Xushan,

Why can you not use the PACK intrinsic directly given its GENERIC capabilities as shown in Quote #5?  Why do you at all need a wrapper subprogram like the one you show in your original post?

0 Kudos
xsl
Beginner
697 Views

FortranFan wrote:

Quote:

Lu, Xushan wrote:

 

.. My goal is to have some subroutine which takes care of this packing process regardless of the array data types. Without this data polymorphism, I need to write numerous codes for different types of data, intrinsic or user-defined.  ..

 

 

@Lu, Xushan,

Why can you not use the PACK intrinsic directly given its GENERIC capabilities as shown in Quote #5?  Why do you at all need a wrapper subprogram like the one you show in your original post?

The purpose here is that sometimes I would like to reallocated the original array and assigned the packed array to the original array and sometimes I don't. Besides, I have an error tacking mechanism keep tracking the possible errors so that I can know immediately where is the error if that is related to the pack procedure (e.g., the original array is not allocated or assigned for some reason) and the subroutines which use these pack procedures might be called by multiple subroutines from multiple modules hence it would be impossible to tell which subroutine does the error belong to whenever it happens.

0 Kudos
Reply