- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think that calling MOVE_ALLOC() with an array subsection should be caught at compile time.
Similar issues are caught at compile time such as passing ARRAY(:) to a procedure requiring an allocatable argument; the standard says FROM shall be allocatable; and other compilers I tried catch it at compile time.
# move_alloc bug
ifort(1) allows subsections on FROM on MOVE_ALLOC() but then sometimes
get ICE, always get entire array with subsection specification ignored
if successful.
Expect error message at compile time indicating FROM is not allocatable
when a subsection is specified.
##
```fortran
program testit
integer,allocatable :: i(:),j(:)
integer :: stat
character(len=256) :: errmsg
i=[1,2,3,4,5,6,7,8,9,10]
call move_alloc(i(::2),j,stat,errmsg)
call printit()
call move_alloc(i(:),j,stat,errmsg) ! segfault
call printit()
contains
subroutine printit
if(stat.ne.0)then
write(*,'(a)')'<ERROR>'//trim(errmsg)
stop
endif
write(*,*)allocated(i),allocated(j)
write(*,*)j
end subroutine printit
end program testit
```
## Results
```text
F T
1 2 3 4 5 6
7 8 9 10
F F
forrtl: severe (408): fort: (8): Attempt to fetch from allocatable variable J when it is not allocated
Image PC Routine Line Source
bug1 0000000000404AA0 testit_IP_printit 17 bug1.f90
bug1 000000000040470D MAIN__ 9 bug1.f90
bug1 000000000040415D Unknown Unknown Unknown
libc-2.31.so 00007FBEC358C083 __libc_start_main Unknown Unknown
bug1 000000000040407E Unknown Unknown Unknown
```
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@ur, Thank you for reporting this.
@FortranFan, Thanks for the simplified reproducer.
I filed a bug report, CMPLRLLVM-42905. Both ifx and ifort should be reporting the error.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On the line 19 call to move_alloc, the array i was deallocated from the move_alloc on line 17.
Note, while line 17 uses a strided source, the whole array of the array descriptor i was deallocated.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
program testit
integer,allocatable :: i(:),j(:)
integer :: stat
character(len=256) :: errmsg
i=[1,2,3,4,5,6,7,8,9,10]
call move_alloc(i(::2),j,stat,errmsg)
call printit()
i=[1,2,3,4,5,6,7,8,9,10]
call move_alloc(i(:),j,stat,errmsg) ! segfault
call printit()
contains
subroutine printit
if(stat.ne.0)then
write(*,'(a)')'<ERROR>'//trim(errmsg)
stop
endif
write(*,*)allocated(i),allocated(j)
write(*,*)j
end subroutine printit
end program testit
Good point; was combining failures. The edit mode does not let me remove the inserted block; but correcting it to reallocate it then lets it run instead of segfaulting; the line is still not legal, as VAR(:) is not an allocatable argument, although it intuitively seems the same as VAR.
For example, ifort will not allow this to compile:
program testit
integer,allocatable :: i(:)
i=[1,2,3,4,5,6,7,8,9,10]
call printit(i)
call printit(i(:))
contains
subroutine printit(i)
integer,allocatable :: i(:)
write(*,*)allocated(i)
write(*,*)i
end subroutine printit
end program testit
!$ ifort testit.f90
!testit.f90(6): error #7851: If dummy arg is allocatable, actual arg must be a !whole array and not a section. [I]
! call printit(i(:))
!----------------^
!compilation aborted for testit.f90 (code 1)
!
!$ gfortran testit.f90
!testit.f90:6:16:
!
! 6 | call printit(i(:))
! | 1
!Error: Actual argument for 'i' must be ALLOCATABLE at (1)
If I create a subroutine with allocatable arguments and pass it an allocatable value with the syntax VAR(:) instead of VAR ifort/ifx reports that as trying to pass an unallocatable argument, for example. The compiler is ignoring that a subsection has been specified, which I argue is incorrect. passing VAR(::2) is not the same as passing VAR.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>VAR(:) is not an allocatable argument
This is correct, same with var(::2).
I pointed out that i was deallocated, even though the i(::2) was invalid.
This compiler bug should be added to the TO DO list.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FWIW (observation)
There are some subtle issues to resolve.
Consider:
call move_alloc((i(::2)),j,stat,errmsg)
The argument "(i(::2))", assuming heap-arrays enabled, generates a non-strided allocatable temporary copy of the strided data.
Does this satisfy the requirement that the from argument be allocatable?
Note, if the strided descriptor (sans enclosing ()'s) is NOT passed to the underlaying move_alloc procedure, then this syntax will generate a non-strided temporary, and if heap-arrays is enabled, this too will then be an allocatable argument.
This should be catchable by the front-end.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I had similar questions, but could not find anything that conditionally allowed a subsection with the second example. For example:
$ ifort -heap-arrays bug2.f90
bug2.f90(6): error #7851: If dummy arg is allocatable, actual arg must be a whole array and not a section. [I]
call printit(i(:))
----------------^
Note if you did want to conditionally allow it when the temporary is arguably allocatable it appears to currently be ignoring the subsection specification, as all the array is returned, not just every other as specified by the i(::2) syntax. I was curious if that would still be true with the heap switch on; it still returned the entire array.
FROM has to have intent(INOUT) anyway, so it can be deallocated. That adds another complication. If the temporary is allocatable would the argument still have to be? Does the original variable still get deallocated? the heap size would change whether the same line were OK or not;
might be doable but starts to sound pretty complicated.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, I was combining some test cases. Should have paid more attention to the failure becoming a segfault when I combined them
This showed up when someone was testing if they got a performance improvement changing some statements that used array syntax to use MOVE_ALLOC instead, and changed one too many lines and did one with a subsection and got the entire array copied instead of getting an error, which introduced a bug. I was debating on whether when the whole array was passed but with a subsection (ie. "i(:)") if it should be OK (it should not be, I decided) even though in some ways it is the same values and threw that on in the example too, but incorrectly, as you noted. Thanks for catching that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If we are to assume your subroutine printit is to print/file an array and otherwise not allocate/deallocate/move_alloc the array, then the dummy argument should not have the allocatable attribute.
>>FROM has to have intent(INOUT) anyway, so it can be deallocated.
In the general usage of move_alloc, the FROM argument is typically a procedure temporary allocated array that is sized and filled with initial data and then who's descriptor is moved from the from to the to (pre-deleting to if necessary, and "nulling out" the from descriptor). This operation does not perform an unnecessary copy and the from descriptor is not actually deleted (as the data now resides at the to discriptor's location), but rather marked as if deleted.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
printit is just a placeholder for a procedure with an allocatable array. It has no other purpose. It prints to give it something to do.
Ideally the data is not deleted just pointed to for efficiency, but not required by the standard. The allocation status still has to be changed on the FROM variable, which is probably why the standard definition states FROM must have intent(INOUT). How the system tracks the allocation status is left up to the compiler as far as I know, and could be anything from a state variable that is part of the allocatable object or kept in a table somewhere or anything else that tracks the state in I suppose but the standard does specify it have that intent.
16.9.137 MOVE_ALLOC (FROM, TO [, STAT, ERRMSG])
1 Description. Move an allocation.
2 Class. Subroutine, pure if and only if FROM is not a coarray.
3 Arguments.
FROM may be of any type, rank, and corank. It shall be allocatable and shall not be a coindexed object.
It is an INTENT (INOUT) argument.
TO shall be type compatible (7.3.2.3) with FROM and have the same rank and corank. It shall be
allocatable and shall not be a coindexed object. It shall be polymorphic if FROM is polymorphic.
It is an INTENT (OUT) argument. Each nondeferred parameter of the declared type of TO shall
have the same value as the corresponding parameter of the declared type of FROM.
STAT (optional) shall be a noncoindexed integer scalar with a decimal exponent range of at least four. It is an
INTENT (OUT) argument.
ERRMSG (optional) shall be a noncoindexed default character scalar. It is an INTENT (INOUT) argument.
So I am thinking since it specifies FROM must be allocatable, and must have INTENT(INOUT) that even though the idea of allowing a temp to be created for an array subsection that was allocatable that TO could point to it would be a non-standard extension even though an interesting idea. Since I can already do "i=i(::2)" instead of the MOVE_ALLOC() my guess it would be hard to get that adopted and let MOVE_ALLOC be specifically for reassigning existing storage. Accept for efficiency I actually like Fortran array syntax. It seems so much more natural. I would have liked something simple like j << i to have meant "assign values of i to j and deallocate j" or something like that instead of MOVE_ALLOC or games with pointers but we have found several places where nice and neat array syntax was significantly slower than MOVE_ALLOC, which is really the reason MOVE_ALLOC exists I would suppose.
PS: As noted gfortran does not let the MOVE_ALLOC example. nvfortran does not either:
NVFORTRAN-F-0507-The arguments to MOVE_ALLOC must be ALLOCATABLE - (bug3.f90: 7)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think you misunderstood me on INTENT(OUT)
The from argument, from the perspective of (scope) within the move_alloc procedure is as if its dummy argument is declared with ALLOCATABLE, INTENT(INOUT). N.B. move_alloc is likely written in C/C++ and the language has no INTENT, nor dummy arguments.
From's caller's perspective (scope), it need minimally be ALLOCATABLE.
Note, for an allocatable array declared within a procedure calling move_alloc, it cannot have an INTENT(...) as INTENT is available only to the dummy arguments of the procedure (if any).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@ur ,
Re: "I think that calling MOVE_ALLOC() with an array subsection should be caught at compile time," - note the following:
- it looks like a new feature request for Intel Fortran and something many customers of Intel Fortran will appreciate but it will take some convincing, I think, for you to get the Intel software team to implement something. Because the standard does not have, if I recall correctly (it's possible I'm wrong), a numbered constraint or syntax rules to require the compiler to detect and report this
It may then help you if you can keep it really, really brief with your code example and cut out all the needless verbosity and simply illustrate to Intel team how IFX can do better, say like so:
integer, allocatable :: a(:), b(:)
call move_alloc( from=a(1:2), to=b ) !<-- an array section is not a whole object and thus not allocatable
end
- A processor out there shows it is detectable at compile-time an array section is not allocatable
C:\Temp>gfortran -c p.f90
p.f90:2:25:
2 | call move_alloc( from=a(1:2), to=b )
| 1
Error: 'from' argument of 'move_alloc' intrinsic at (1) must be ALLOCATABLE
C:\Temp>
- So that IFX can do better
C:\Temp>ifx /c /standard-semantics p.f90
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2022.1.0 Build 20220316
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\Temp>
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@ur, Thank you for reporting this.
@FortranFan, Thanks for the simplified reproducer.
I filed a bug report, CMPLRLLVM-42905. Both ifx and ifort should be reporting the error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There's a lovely error message now for both ifx and ifort in the latest compiler versions available in oneAPI HPC Toolkit 2023.1.
Try it!
+ ifx -what -c section.f90
Intel(R) Fortran 23.0-1474.2
section.f90(2): error #8195: The argument to the MOVE_ALLOC intrinsic subroutine shall be an allocatable object. [MOVE_ALLOC]
call move_alloc( from=a(1:2), to=b ) !<-- an array section is not a whole object and thus not allocatable
-------------------------^
compilation aborted for section.f90 (code 1)
+ ifort -what -c section.f90
Intel(R) Fortran 2021.9.0-1497
section.f90(2): error #8195: The argument to the MOVE_ALLOC intrinsic subroutine shall be an allocatable object. [MOVE_ALLOC]
call move_alloc( from=a(1:2), to=b ) !<-- an array section is not a whole object and thus not allocatable
-------------------------^
compilation aborted for section.f90 (code 1)
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page