Silverfrost Forums

Welcome to our forums

Using un-allocated arrays as subroutine arguments

12 Jun 2014 3:10 #14159

I have been trying to use allocatable variables as subroutine arguments and I am investigating what happens if the arrays have not previously been allocated.

I am not sure if the Fortran 95 standard allows un-allocated arrays as arguments, but FTN95 Ver 7.00 appears to do this. The following example shows the test code I have written.

!  Program to test allocate
!
     call test_alloc
     end

     subroutine test_alloc
!
     real*8, allocatable, dimension(:,:) :: aa, bb
!
     allocate ( aa(4,7) )
!
     if (allocated (aa)) then
       write (*,*) 'aa is allocated'
     else
       write (*,*) 'aa is NOT allocated'
     end if
!
     if (allocated (bb)) then
       write (*,*) 'bb is allocated'
     else
       write (*,*) 'bb is NOT allocated'
     end if
!
     write (*,*) 'Size test 1'
     write (*,*) size (aa)
     write (*,*) size (bb)    !  this gives a non-zero result with /debug
!                                but fails with /check
!                                should it work and return 0 ?
!
!  Call routine with un-allocated array bb
     call test_call (aa, bb)
!
     write (*,*) 'aa=',aa(1,1)
!
     write (*,*) 'Size test 2'
     write (*,*) size (aa)
     write (*,*) size (bb)
!
     end subroutine test_alloc

     subroutine test_call (aa, bb)
!
     real*8 aa(4,*), bb(6,*)   ! what declaration should work for Fortran 95 ?
!
     aa(1,1) = 1.0
!
!  The following will compile and work with FTN95 /debug
     if (allocated (aa)) then
       write (*,*) 'aa is allocated'
     else
       write (*,*) 'aa is NOT allocated'
     end if
!
     if (allocated (bb)) then
       write (*,*) 'bb is allocated'
     else
       write (*,*) 'bb is NOT allocated'
     end if
!
     end subroutine test_call

The above program aa.f90: works for ftn95 aa /lgo works for ftn95 aa /debug /lgo fails for ftn95 aa /check /lgo I think that FTN95 may not conform to the Fortran 95 standard ?

I am trying to avoid making the arrays allocated, so that I can utilise the status of .not. allocated (bb) in the subroutine. I think F2003 and F2008 have changed the way these arguments may be declared and handled.

Any comments ?

John

12 Jun 2014 7:07 #14160

To check for standard conforming code, use /ISO on the command line. FTN95 gives a warning when /ISO is not used and an error report when it is used.

It looks like /CHECK is not clever enough to handle this code.

12 Jun 2014 9:37 #14162

Paul,

Thanks for the suggestion. I used the /ISO which indicated that I had a problem with the ALLOCATED test in the subroutine.

From the Fortran 95 Draft Standard J3/97-007R2: 13.14.9 The ALLOCATED intrinsic can only be applied to an allocatable array. 5.1 The ALLOCATABLE attribute may be used only when declaring an array that is not a dummy argument or a function result. This implies that I can not test the allocated attribute of an aray in a subroutine.

In the case of the SIZE () intrinsic; 13.14.101 SIZE (ARRAY [, DIM]) Returns the extent of an array along a specified dimension or the total number of elements in the array. ARRAY may be of any type. It shall not be scalar. It shall not be a pointer that is disassociated or an allocatable array that is not allocated. This implies that I can not use SIZE on an array that is not allocated.

In the case of an actual argument to a subroutine call being ALLOCATABLE, I can not find any specification in the standard relating to the actual argument must be ALLOCATED.

The basic problem with the code I have is can I use an un-allocated array as the argument in a subroutine call ?

John

12 Jun 2014 5:48 (Edited: 13 Jun 2014 7:11) #14165

Hello John,

I don't think the Fortran standard allows you to use allocated() on [u:84323fff19]assumed size[/u:84323fff19] dummy argument arrays (such as aa(4,*)). As your code stands there would be no way for the compiler to know about the allocation status of aa if your test_call was compiled in a separate file.

You would need to use [u:84323fff19]assumed shape[/u:84323fff19] (aa(:,:)) and then you would also need an explicit interface to test_call().

Something like this should work:

module foo
contains
   subroutine process(a)
      real, allocatable :: a(:) 
      if (allocated(a)) then
          ! ... do something if a is allocated
      else
         ! ... do something if a not allocated
      end if
   end subroutine process
end module foo

program test
   use foo

   real, allocatable :: a(:)

   call process(a)

end

If there is a bug in FTN95 preventing allocated() from working (I don't think there is), you can allocate a zero size array and test this to see if the array is in use. But you would still need to use assumed shape and an explicit interface.

   allocate(aa(0))

   if (size(aa) > 0) then
          ! ... do something if a is being used
   else
         ! ... do something if a not being used
   end if

David.

13 Jun 2014 12:45 #14169

David,

Thanks for your comments. The problem I have is that the following program appears to work with /debug, although it gives a warning about the use of ALLOCATED().

!  Program to test use of allocated intrinsic
!
     real*8, allocatable, dimension(:,:) :: aa, bb
!
     allocate ( aa(4,7) )
!
     call test_call (aa, bb)
!
     write (*,*) 'aa=',aa(1,1)
!
     end

     subroutine test_call (aa, bb)
!
     real*8 aa(4,*), bb(6,*)   ! what declaration should work for Fortran 95 ?
!
     aa(1,1) = 1.0
!
!  The following will compile and work with FTN95 /debug
     if (allocated (aa)) then
       write (*,*) 'aa is allocated'
     else
       write (*,*) 'aa is NOT allocated'
     end if
!
     if (allocated (bb)) then
       write (*,*) 'bb is allocated'
     else
       write (*,*) 'bb is NOT allocated'
     end if
!
     end subroutine test_call

My problem is: Can I assume that the 'call test_call (aa, bb)' can be expected to work, where bb has not been allocated ? (ie not give an access violation error) Can I assume that allocated (bb) will give a valid result, although I can use other tests to identify if bb has not been allocated.

The alternative is to provide tests for all allocatable arrays, before the call test_call takes place. For example I could do this for bb in the following example, although I would subsequently need to test and de-allocate bb (and all similar arrays) when it is required to be allocated.

!  Program to test use of allocated intrinsic
!
     real*8, allocatable, dimension(:,:) :: aa, bb
!
     allocate ( aa(4,7) )
!
!  prepare for test_call
     if (.not. allocated (aa)) allocate ( aa(4,0) )
     if (.not. allocated (bb)) allocate ( bb(6,0) )

     call test_call (aa, bb)
!
     write (*,*) 'aa=',aa(1,1)
!
     end

I was trying to avoid the complexity of manageing (and reporting) the testing for allocation of arrays like bb, but it probably looks like the best approach. I should also look at F2003/2008 and see how the standard has managed this.

John

13 Jun 2014 7:20 #14171

Quoted from JohnCampbell

Can I assume that the 'call test_call (aa, bb)' can be expected to work, where bb has not been allocated ? (ie not give an access violation error) Can I assume that allocated (bb) will give a valid result, although I can use other tests to identify if bb has not been allocated.

No to both. It isn't valid Fortran

If the code works with /DEBUG then that is just a quirk of this compiler.

You always need the ALLOCATABLE attribute on the array to use ALLOCATED. To do what you want, the dummy array must have the allocatable attribute like this:

subroutine test_call(aa, bb)
real*8, allocatable :: aa(:), bb(:)
if (allocated(aa)) then
   write(*,*) 'aa is allocated'
else
   write(*,*) 'aa is NOT allocated'
end if

if (allocated(bb)) then
   write(*,*) 'bb is allocated'
else
   write(*,*) 'bb is NOT allocated'
end if

end subroutine test_call
13 Jun 2014 8:36 #14173

davidb wrote: You always need the ALLOCATABLE attribute on the array to use ALLOCATED.

Unfortunately, Clause 5.1 of the standard includes : The ALLOCATABLE attribute may be used only when declaring an array that is not a dummy argument or a function result. This implies that I can not define the dummy argument as allocatable and so can't test the allocated attribute of the array in the subroutine. I must test it before the routine is called.

I can't see a way around this.

John

13 Jun 2014 2:59 #14177

My understanding is that this is a deliberate FTN95 extension to the standard. The reason behind the /ISO switch is that FTN95 has some non standard extensions and so one needs to use /ISO to ensure conformance with the Standard.

Naturally for portable code one should use /ISO but if you are locked into FTN95 then the extensions are there to use.

Admittedly there is a problem with /CHECK but this ought to be fixable.

However, I have not followed this thread closely so I may be missing the point.

13 Jun 2014 4:18 #14186

[quote='JohnCampbell']

[quote:ed7c457665]Unfortunately, Clause 5.1 of the standard includes : The ALLOCATABLE attribute may be used only when declaring an array that is not a dummy argument or a function result. John

This is the case for Fortran 95, but the allocatable attribute is [u:ed7c457665]allowed[/u:ed7c457665] in Fortran 2003. You have stumbled across a deficiency in the Fortran 95 language that has been corrected in Fortran 2003.

Paul,

I am not sure that you can implement this as an extension to the standard. It is forbidden to use the allocated() intrinsic on an array which does not have the allocatable attribute. In Fortran 95, only allocatable deferred shape arrays can be used. In Fortan 2003 (and later), allocatable deferred shape and allocatable dummy arrays can be used.

Even if you break the rules as an extension, there is no easy way to get the allocation status of an assumed size array when a subroutine is compiled in a separate file.

14 Jun 2014 6:33 #14189

David

I have not looked at this closely but my comments relate to the current state of FTN95. As I understanding it, FTN95 can provide any extensions that are feasible but I don't know if this is the case here.

John

If this is a significant issue then I can log it for further investigation if you wish.

14 Jun 2014 8:25 #14191

If you make aa and bb pointer arrays I think you should be able to pass them as unallocated, and keep them as allocated after return from the subroutine. But you do need to nullify them first, otherwise the results are unexpected. There is some way of avoiding the compilers warning message about the use of allocated on non-allocatable arrays (withohut simply suppressing the message), but I can't remember what that is right now

!  Program to test use of allocated intrinsic
!
     real*8, pointer, dimension(:,:) :: aa, bb
!
     nullify (aa)
     nullify (bb)
     allocate ( aa(4,7) )
!
     call test_call (aa, bb)
!
     write (*,*) 'aa=',aa(1,1)
!
     contains
     subroutine test_call (aa, bb)
!
     real*8, pointer, dimension(:,:) aa, bb   ! what declaration should work for Fortran 95 ?
!
     aa(1,1) = 1.0
!
!  The following will compile and work with FTN95 /debug
     if (allocated (aa)) then
       write (*,*) 'aa is allocated'
     else
       write (*,*) 'aa is NOT allocated'
     end if
!
     if (allocated (bb)) then
       write (*,*) 'bb is allocated'
     else
       write (*,*) 'bb is NOT allocated'
     end if
!
     end subroutine test_call
     end
Please login to reply.