- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The last example in
explains the case of (re)allocate-on-assignment for unlimited polymorphism.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page