I tried to compile this program with two different versions of gfortran:
program main
integer, dimension(1:2) :: iii
real, dimension(1:4,1:4,1:2) :: myArray
associate(iix => iii(1), iiy=> iii(2) )
forall( iix=1:4, iiy=1:4 )
myArray(iix,iiy,1) = iix + iiy
myArray(iix,iiy,2) = (iix + iiy)*10
endforall
end associate
print *, myArray(:,:,1)
print *, myArray(:,:,2)
end program main
There is no problem with GNU Fortran (GCC) 12.1.1 20220507 (Red Hat 12.1.1-1)
version
But with GNU Fortran (Debian 10.2.1-6) 10.2.1 20210110
version, I get a compilation error
7 | forall( iix=1:4, iiy=1:4 ) | 1 internal compiler error: Segmentation fault
This version is not so old (2021/01/10)
From which gfortran version, is it possible to use associate
in a forall
statement?
And does this program conform to the standard?
It works with do
loops
integer, dimension(1:2) :: iii
real, dimension(1:4,1:4,1:2) :: myArray
associate(iix => iii(1), iiy=> iii(2) )
do iix = 1,4
do iiy = 1,4
myArray(iix,iiy,1) = iix + iiy
myArray(iix,iiy,2) = (iix + iiy)*10
enddo
enddo
end associate
print *, myArray(:,:,1)
print *, myArray(:,:,2)
end program main
Following the comment of Jonathan Wakely, I sum up. In my initial code, there is also a do
loop between the associate
line and the forall
line.
program main
integer, dimension(1:2) :: iii
real, dimension(1:4,1:4,1:2) :: myArray
integer :: i
myArray = 0.0
associate( iix => iii(1), iiy => iii(2) )
do i=1,2
forall( iix=1:4, iiy=1:4 )
myArray(iix,iiy,i) = (iix+iiy)*10*i
endforall
enddo
end associate
print *, myArray(:,:,1)
print *, myArray(:,:,2)
end program main
In comments we've addressed that the failure to compile with GCC 10 is a compiler bug which has been fixed in/by GCC 12. You offered to report this bug, but Jonathan Wakely has identified where this was fixed: there's little point reporting.
That said, there's still something we can say about code validity and workarounds.
Actually, I won't comment on validity, because what I'll say about the code itself makes that concept redundant.
Based on previous questions you've asked, you're using the ASSOCIATE with the FORALL to allow you to use an array element as the index. Something like
integer :: i(2)
forall (i(1)=1:4) ...
isn't allowed, so like with DO constructs and arrays you're associating a scalar variable with the element.
With FORALLs, though, that's entirely unhelpful.
The scope of an index in a FORALL statement/construct is that statement/construct. There's no connection between the array iii
(in the question example) outside the FORALL and inside. There's simply no point associating the arrays elements with scalars to use those scalars in the FORALL.1
Note that you can2 "create" a new name specific to the FORALL itself, so you don't need to re-use names:
forall (integer :: iix=1:4, iiy=1:4, iiz=1:4) ...
instead of
integer iii(3)
associate (iix=>iii(1), iiy=>iii(2), iiz=>iii(3)
forall (iix=1:4, iiy=1:4, iiz=1:4) ...
end associate
FORALLs and DOs are very different things.
Some Fortran developers would say that the appropriate workaround for GCC 10 is to simply avoid using FORALLs at all. FORALLs are obsolescent in the Fortran standard and may be removed in the future. It's a reasonable position to hold that they should be avoided in new code.
1 If you don't have compiler support for what I mention next, then there is a (weak) point in using an ASSOCIATE to tidy up the number of declared scalar variables - in this case use a BLOCK construct to at least keep them local. It's hard to see the ASSOCIATE example above as any tidier than
block
integer iix, iiy, iiz
forall (iix=1:4, iiy=1:4, iiz1:4) ...
end block
Or avoid the obsolescent FORALL altogether.
2 If you have compiler support for this Fortran 2008 feature. GCC at the time of answering is missing this support.