Allocatable function results -- must they be allocated?

Where in the standard can I find language that requires an ALLOCATABLE function result to be in the allocated state at the end of the function’s execution – or that discusses what should happen in the expression containing the function reference if it is not allocated?

Section 5.4.10

An unallocated allocatable variable shall not be referenced or defined.

As the result of a function necessarily is in an expression, it will be referenced. Thus, the result of an allocatable function must be allocated.

It’s a bit of roundabout reasoning. Worth suggesting an edit to the standard to make explicit I think.

Several important Fortran compilers happily compile PRINT *, SUM(FOO()), run, and print 0 where FOO is a function whose result is allocatable but unallocated; I’m trying to figure out whether that’s required & conforming behavior or an extension that I need to worry about supporting.

I’d say that’s in “undefined behavior” territory, and you’d be perfectly within reason to not support it.

Fortran confusingly defines a reference as using the value of a data object to determine the value of an expression, and in the case above one could argue that the value of the allocatable is not being used because the shape is somehow interpreted as being empty, and a shape is a characteristic of a value. The SHAPE() intrinsic is disallowed for an unallocated allocatable variable, but the result of a function is not a variable unless it’s a pointer. See the note in 8.5.3 – the result of an allocatable function is not allocatable.

So I’m still not sure what’s required.

On Windows, gfortran, g95, Intel Fortran, and on WSL flang clang 7.0.1 all just print 0 for the code

integer, allocatable :: ivec(:)
print*,sum(ivec)
end

so at least they are consistent.

That example does not contain an allocatable function result, though.

I would argue that the SHAPE is either a component of its value or its value must be referenced to determine it. Variable or not, the use of something that is not allocated is not standards conformant.

In each of the standard revisions starting Fortran 2003, the equivalent of section 15.6.2.2 Function subprogram in 18-007 document toward Fortran 2018 has included the statement, “If the function result is not a pointer, its value shall be defined by the function.” The definition of the value will involve allocation when the function result is ALLOCATABLE.

Now this is a programmer responsibility that a good processor may choose to help enforce via suitable diagnostics.

19.3.3 Function results
1 For each FUNCTION statement or ENTRY statement in a function subprogram, there is a function result. A function result is either a variable or a procedure pointer, and thus the name of a function result is a local identifier of class (1).

Doesn’t that show that language in SUM and SIZE referring to variables should also refer to function results? SUM is transformational so allocatable array argument must be allocated and their shape must be defined. Furthermore, SHAPE (an inquiry function) forbids unallocated allocatables.

The “function result” within the body of the function is, as described in 19.3.3, an object like any other variable or procedure pointer. The “function result” that is used by the caller of the function as the value of the function reference is a distinct concept – it is a variable if and only if the function returns a data pointer. Easy to confuse the two.

module m
  integer, target :: x
 contains
  function f1() result(res1)
    integer, pointer :: res1
    res1 => x
  end function
  function f2() result(res2)
    integer, allocatable :: res2
    allocate(res2, source=666)
  end function
end module

use m
f1() = 123 ! OK: f1() is a variable because res1 is a pointer
f2() = 234 ! ERROR: f2() is not a variable, even though res2 is
if (.not. allocated(f2())) stop ! ERROR: f2() is not allocatable, even though res2 is so
end

Ok but I am not sure this is relevant, your SUM(FOO()) does not use FOO() in a variable definition context but in an expression.

Re: “a function whose result is allocatable but unallocated”, it corresponds to code that clearly does not conform. However there are no numbered constraints that require a processor to issue a diagnostic. Thus the onus lies entirely on the programmer, a compiler can choose to be a good one and alert the coder as to the problem.

“Happily” only if warning diagnostics are not requested.

Consider the following:

   function f( a ) result(r)
      integer, intent(in) :: a
      integer, allocatable :: r
      ! dummy instruction to make the processor do something here; not required
      if ( a < 0 ) error stop 
   end function 

C:\Temp>gfortran -c -Wreturn-type f.f90
f.f90:1:28:

1 |    function f( a ) result(r)
  |                            1

Warning: Return value ‘r’ of function ‘f’ declared at (1) not set [Warning Options (Using the GNU Compiler Collection (GCC))]

C:\Temp>ifort /c /warn f.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.2.0 Build 20210228_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.

f.f90(1): warning #6178: The return value of this FUNCTION has not been defined. [R]
function f( a ) result(r)
--------------------------^
f.f90(1): remark #7712: This variable has not been used. [R]
function f( a ) result(r)
--------------------------^

C:\Temp>

I think this is the sentence in the standard that is relevant: " If the function result is not a pointer, its value shall be defined by the function." If the function result is allocatable, it has to be allocated in order to be defined.

1 Like

Thanks, Bill. I think that’s good enough for me.

1 Like