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

Applying "allocated" function to "associate" variables

Jarek_T
Novice
816 Views

I have a code with using nested derived types where some "leaf" variables have rather long names. To keep the code readable I often copy scalar variables to much shorter local variables and use "associate" statement to do the same with the arrays. That works great except for "allocated" function which does not seem to work with associated variables.

 

For example, in the code:

 

program associate_test
   implicit none
   integer, allocatable :: ivec(:)

   allocate ( ivec(5) )
   associate ( jvec => ivec )
      if (allocated(jvec)) then
         jvec = 0
      end if
   end associate
end program

 

the variable "ivec" is really some very long name with couple "%" symbols. The above code does not compile, giving me the following errors:

1>------ Build started: Project: line_test (IFX), Configuration: Release x64 ------
Compiling with Intel® Fortran Compiler 2024.2.1 [Intel(R) 64]...
test.f90
test.f90(7): error #7397: The argument of the ALLOCATED inquiry intrinsic function should have the ALLOCATABLE attribute.   [JVEC]
test.f90(7): error #8306: Associate name defined in ASSOCIATE or SELECT TYPE statements doesn't have ALLOCATABLE or POINTER attribute.   [JVEC]
compilation aborted for test.f90 (code 1)

In this toy example I can easily change "allocated(jvec)" to "allocated(ivec)" and it will compile, but I am trying to understand if I am doing something wrong here. The message "Associate name defined in ASSOCIATE [] statement doesn't have ALLOCATABLE [] attribute. [JVEC]" suggests that I can add allocatable attribute to associate variable "jvec" somehow. How do I do that?

 

0 Kudos
7 Replies
Steve_Lionel
Honored Contributor III
773 Views

No, it doesn't suggest that. The standard says that associate names don't have ALLOCATABLE or POINTER even if the selector does, and you can't change that.

0 Kudos
Jarek_T
Novice
763 Views

Steve, so you are saying that it is by design (standard)  that I can use my new short name ("jvec") with any other intrinsic array function like SIZE, MAXVAL, SHAPE, RESHAPE, MATMUL, etc. but for ALLOCATED I need to use the original long variable name ("ivec").  It is odd that one function will be singled out like that. 

0 Kudos
Steve_Lionel
Honored Contributor III
740 Views

It's not one function - there are many other things that being allocatable or pointer allow, such as reallocation on intrinsic assignment or pointer assignment. The wording in the standard is as follows (emphasis mine):

Within an ASSOCIATE, CHANGE TEAM, or SELECT TYPE construct, each associating entity has the same rank as its associated selector. The lower bound of each dimension is the result of the intrinsic function LBOUND (16.9.119) applied to the corresponding dimension of selector. The upper bound of each dimension is one less than the sum of the lower bound and the extent. The associating entity does not have the ALLOCATABLE or POINTER attributes; it has the TARGET attribute if and only if the selector is a variable and has either the TARGET or POINTER attribute.

andrew_4619
Honored Contributor III
699 Views

Maybe the logic of the program is flawed and you should not ever be associating something is is not allocated ? So ...

program associate_test
   implicit none
   integer, allocatable :: ivec(:)

   allocate ( ivec(5) )
   if (allocated(ivec)) then
        associate ( jvec => ivec )
            jvec = 0
        end associate
  end if
end program

 

0 Kudos
Jarek_T
Novice
653 Views

I guess my issue is that I am using associate statement to give short names for variables where using full name makes code hard to read. Since I very rarely use  array-slices or other more complicated associations, in most cases the behavior is as if I was using C macro expansion, with this single exception (that I found) of allocated function. 

I guess I should stop thinking about it as a macro, and than 5his behavior would not be surprising. 

Thank you all for help.

0 Kudos
jimdempseyatthecove
Honored Contributor III
615 Views

In light of @Steve_Lionel reply I suggest you consider using contained functions to perform the non-associated query and allocate/deallocate

 

associate(ivec => through%the%woods%and%over%the%hill%ivec)
...
if(ivecIsAllocate()) then
  ! do this
else
 if(ivecAllocate(nThings) /=0) stop "allocation error"
endif
contains
function ivecIsAllocate() result(ret)
   ret = isAllocated(through%the%woods%and%over%the%hill%ivec)
end function ivecIsAllocate()
function ivecAllocate(n) result(ret)
  integer :: ret
  allocate(through%the%woods%and%over%the%hill%ivec(n), stat=ret)
end function ivecAllocate
...

 

Or place these functions in a module.

 

Jim Dempsey

IanH
Honored Contributor III
583 Views

 As andrew_4619 perhaps subtly says, if the selector is not allocated, you must not execute any part of an associate construct with that selector (F2023 19.5.1.6p2).  Testing the allocation status from within the construct is pointless - if the selector is not associated then the program is already exploding from a conformance point of view.

Reply