Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there anything wrong with passing an unallocated array to a routine without an explicit interface?

Consider:

program main
real, allocatable, dimension(:) :: foo
integer n
n=10
call dofoo(foo,n,1)
allocate(foo(n))
call dofoo(foo,n,0)
end program main

subroutine dofoo(foo,n,mode)
real foo(n)
integer i,n,mode
if(mode.eq.1)then
   n=6
   return
endif
do i=1,n
   foo(i)=i
enddo
return
end subroutine dofoo

Is there anything wrong with the above code? (It works with gfortran) I pass in an un-allocated array the first time, but I don't touch it -- Is there anything in the standard that could cause this to behave in a system dependent way?

like image 403
mgilson Avatar asked Nov 21 '12 15:11

mgilson


2 Answers

You've almost answered your own question. Yes, by the standard, it is always illegal to pass an unallocated allocatable arrays as an actual argument if you don't have an interface in scope.

If you have an interface in scope it is only legal if the dummy argument is also allocatable.

And yes I've been bitten by it. My work around has been to allocate to zero size before the call.

like image 163
Ian Bush Avatar answered Oct 10 '22 22:10

Ian Bush


The answer by Ian Bush correctly states that the use in the question is not allowed. We can be more precise, though. (References in parentheses to the Fortran 2018 standard.)

There are three cases where an unallocated allocatable actual argument may be used:

  • when the dummy argument is also allocatable (only since Fortran 2003, or Fortran 95+TR-15581) (15.5.2.6 p.2)
  • when the dummy argument is an optional ordinary argument (only since Fortran 2008) (15.5.2.12 p.1, 15.5.2.4 p.7)
  • when the procedure is an intrinsic inquiry function (15.5.2.4 p.7, 16.1 p.2)

There is no exception for "unused" dummy arguments. These restrictions apply whether the allocatable argument is an array or a scalar.

Any other use means that the program is non-conforming (15.5.2.4 p.7, 15.5.2.7 p.2).

In a conforming program, each of these acceptable cases has an explicit interface available. An allocatable or optional dummy argument requires one (15.4.2.2 p.1(3)) and an accessible intrinsic procedure always has an explicit interface available (15.4.2.1 p.1).

These requirements on the program are not ones a compiler is required to be able to analyse. Such a non-conforming program doesn't necessarily mean that you will see problems when compiling and running. In the case of the program of the question, which doesn't attempt to dereference in a bad way, you may well get away with it. However, it's not good to write non-conforming programs and very bad to rely on them "working".

There are some ways where things may go wrong:

  • run-time checks
  • compile-time checks
  • the dummy having the value attribute (again, explicit interface required in this case)

That is, your program could behave differently with some compilers/compiler options. Your compiler may refuse to compile the program if it notices that you should have an explicit interface available. The program may abort when entering the subroutine if the runtime checks whether the argument is allocated. The runtime may do something very unexpected if trying to make an anonymous definable copy of the array with the value attribute when the actual argument isn't allocated.


For the question there's another non-compliance to worry about. The explicit-length dummy argument foo(n) means that the actual argument must have at least n elements. An unallocated array doesn't have at least n elements (for any, even zero, n). If foo was intent(out) a compiler would be within its rights doing something to "undefine" these elements of the actual argument. This may fail.

like image 27
francescalus Avatar answered Oct 10 '22 20:10

francescalus