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

2

8

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?

Marcheshvan answered 21/11, 2012 at 15:28 Comment(0)
M
7

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.

Mcdevitt answered 21/11, 2012 at 15:44 Comment(12)
Thanks. I was worried that this was the case. I didn't know what the standard had to say (I'm very familiar with the f77 standard, but I haven't actually read most of the f90 standard)Marcheshvan
As a side note, the code above works with gfortran (after I edited out the bugs)Marcheshvan
Passing around allocatable arrays wasn't cleared up until a TR to the F95 standard. Allocated status & dimensions are part of the allocatable array variable. That matters because things like intent(in) or intent(out) then tell you not just if values of array can change but whether it's sizes or allocation status can change. Without an explicit interface, a program would have to assume the worst when passing an allocatable array - it may not even know the size any more on return. That is a huge performance penalty in the usual case, so it was decided that one must have explicit interface.Editorial
@JonathanDursi -- Are you saying that I can't even pass an allocated array to a routine without an explicit interface? -- That has HUGE implications for working with legacy code ... e.g. I can't allocate an array and then pass it to BLAS ...Marcheshvan
@Marcheshvan no; just that it wasn't cleared up until F95/F2003. The Fortran committee is relentlessly, remorselessly, obsessed with backwards compatibility, so it's often ok, but as Ian Bush points out, there are corner cases like unallocated arrays which don't work. Which makes sense; an "unallocated array" wasn't even a thing before F90, so naturally it won't work with F77 code. On the other hand, an array of fixed non-negative size from some calling routine is fine. If you're doing things that you couldn't do before F90, you'll probably need explicit interfaces. If not, probably not.Editorial
@JonathanDursi -- Phew! You had me worried for a moment there :). And just to be painfully clear, you mean if I'm doing things in the called subroutine that I couldn't do pre-F90 then I need an interface. The calling program block can still do whatever it wants (allocate an array to pass, etc).Marcheshvan
... unless the thing being passed is "weird" in some way like an unallocated array, but yeah. (Imagine how bad it would be if you couldn't pass allocated matrices to BLAS/LAPACK routines). Sorry for being unclear.Editorial
In my humble segmently violated experience, both ifort and gfortran pass unallocated arrays as null references to routines without explicit interface.Indemnity
"If you have an interface in scope it is only legal if the dummy argument is also allocatable." Don't forget that since F2008 this is no longer true.Stephi
@Stephi Ahhh yes. I presume this is using an unallocated array to indicate an absent, non-allocatable, non-pointer optional argument. Are there any other exceptions?Mcdevitt
It is (and I recall how you've previously said how much you love this feature). The other exception (which isn't "new") is for intrinsic inquiry functions, but that's a slightly different case.Stephi
Thank you for confirming, and yes, I guess the query functions should also count. Luckily it is only early afternoon, I should be able to sleep tonight.Mcdevitt
S
4

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.

Stephi answered 21/6, 2021 at 14:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.