Can a function with pointer result be forwarded as actual argument?

Consider:

module m
  integer, target :: x = 123
 contains
  function foo() result(p)
    integer, pointer :: p
    p => x
  end function
  integer function bar(q)
    integer, pointer :: q
    bar = q
  end function
end module

use m
print *, bar(foo())
end

Note the absence of INTENT(IN) on the dummy argument q.

Conforming, or not? Every compiler under the sun accepts this program, but I believe that they all are incorrect. My thinking, which may of course be wrong, is that in the context of an actual argument expression, the reference to the function foo() is a “variable”, namely the target of the returned pointer, and not the pointer itself. Unlike the case of a “data-target” in a pointer assignment statement, there’s no special carve-out in actual argument specifications for references to functions whose results are data pointers. (And maybe there should be such a special case, but I can’t find one in F’2018.)

For whatever it’s worth, I think the code conforms to Fortran 2008 and later standard revisions.

Fortran 2008 introduced, “A pointer function reference can denote a variable in any variable definition context.

One can grok through the standard for the semantics introduced with this facility in Fortran 2008, but I don’t see anything that disallows the code in the original post.

The calling code in the original post can be seen as equivalent to

  use m
  integer, pointer :: px
  px => foo()
  print *, bar( px )
end

which is conformant with Fortran 90 and later revisions.

1 Like

Fortran gives you BAR((FOO())) if you want the target. FOO() is a pointer and it is used as the actual argument for (edited) a pointer dummy, so why would the target be involved?

This does not appear right.

Per Fortran standard, a reference to a data pointer is always to a defined target that is associated with said pointer. Such a reference being disallowed when the pointer is not associated with a valid target. So the first sentence in the above quote doesn’t appear relevant to the question in the original post from what I understand.

When it comes to the second sentence involving INTENT(IN), my view is it applies to the automatic targeting facility introduced in Fortran 2008 when the actual argument has the TARGET attribute whereas the corresponding dummy argument has the POINTER attribute; again not relevant here according to my understanding.

For the code in the original post, the function reference foo() in bar( foo() ) function reference appears to be a variable which is a valid data pointer in the scope of foo. Thus in foo, it should
conform to have, say, a pointer assignment q => y where y is some valid target. Say y is defined as 42, the PRINT statement in the main program should then output 42. The standard seems to indicate as such and other compilers appear to agree.

As to a cover from the standard though, perhaps someone else will post here that will be readily accepted as an argument from authority to immediately yield such a thing.

Why can it not be just like a variable that is declared with the POINTER attribute?

It may well need an interp to sort out (i.e. insert the right language to make current usage by compilers correct) but I can’t believe the committee intended to disallow use in this context as a pointer (because it is easy enough to get to the target if that’s what was wanted).

Re: (foo()), the standard allows

   bar( (foo()) )

that would be acceptable, say, when the interface for bar is as follows with the interface of foo being the same as in the original post:

function bar( q )
   integer, intent(in) :: q
..

And here, “a copy of the value of the target” would indeed be involved.

But now, the original post has bar( foo() ) in which case “a copy of the value of the target” does not make sense. Here, one would think foo() gets treated as a variable that is a data pointer, just like I mentioned with px upthread: Can a function with pointer result be forwarded as actual argument? - #2 by FortranFan

I am not attempting to declare authority, but I agree with @FortranFan that the example is conforming.

First, consider 15.3.3 Characteristics of function results (emphasis mine):

The characteristics of a function result are its declared type, type parameters, rank, whether it is polymorphic, whether it is allocatable, whether it is a pointer, whether it has the CONTIGUOUS attribute, and whether it is a procedure pointer

Therefore, foo() is a pointer. The interface to bar specifies that the dummy argument q is a pointer. (As @FortranFan correctly notes, the relevance of intent(in) applies only when the corresponding actual argument is not a pointer.)

I understand the uncertainty, especially given 9.2p1:

A variable is either the data object denoted by designator or the target of the pointer resulting from the evaluation of function-reference; this pointer shall be associated.

but I think the context of the use is important. 15.5.2.5p3 says:

A present pointer dummy argument that corresponds to a pointer actual argument becomes argument associated with that actual argument.

The actual argument is a pointer, so the dummy is associated with it.

I’d be open to clarifying this somehow, but I’m not sure what would work here.

1 Like

Note that INTENT(IN) for a pointer dummy variable only means that the pointer association status of that pointer cannot be changed in the procedure. The value of the target of the pointer can be changed.

1 Like

The OP is asking about standard conformance. A different question is whether one should ever write a function returning a pointer result. Richard Maine said no in comp.lang.fortran 8 years ago

Now my personal recommendation is to assiduously avoid ever using
functions that return pointers. I am quite serious about wishing that
they had not even been introduced into the standard. Use a subroutine
and pass the pointer back via an argument instead. Functions that return
pointers are EXTREMELY error prone. Even experts mess them up at
times. I find it instructive that there was at least one case of someone
here posting an example of such a function that he considered a “safe”
kind of use, but actually had one of the common errors because he was
concentrating on other aspects and missed that error. He even knew
better than that error, but it is an easy one to make anyway.
Unfortunately, some of the common errors are of types that do not tend
to get caught at compile time, but instead cause confusing run-time
behavior.

When smart people say never use feature X it simplifies my life, if not that of compiler writers.

1 Like
  • I fail to see “special” language in the standard or a “special carve-out” of relevance to the primary inquiry about conformance in the original post. As mentioned upthread, Fortran 2008 introduced a pointer function reference in any variable-definition context and it’s as simple as that.

  • Arguably there are a few remnants in the current publication from prior revisions (90, 95, 2003) left over from the time when a pointer function reference was disallowed in a variable definition result that could perhaps do with better phrasing if the standard editor had infinite time and infinite other resources, but I fail to see anything that fundamentally would alter the interpretation offered here.

I would not term it as “special” language or “special” carve-out. BNF and C1025 in current standard appears a less verbose and, dare I say simplified, text of what was there with Fortran 2003. Anyways, the motivating rationale for that particular BNF and constraint might simply be the paired semantics of POINTER <=> TARGET that was meant to provide a more secure way for working with pointers in Fortran toward scientific and technical programs. This is as opposed to anything with actual arguments with function result references.

I fail to see how 19.6.7(10) is relevant here; 19.6.7(10) refers to the situation when the actual argument is a procedure as opposed to a function result reference, the latter being simply a data-pointer vis-a-vis the original post.

In your compiler, pmk, would this

integer, pointer ::z

print *, “associated(foo())”, associated(foo())
z => foo()
print *, bar(z)

print T and 123?

I have to say that 9.2p1

A variable is either the data object denoted by designator or the target of the pointer resulting from the evaluation of function-reference; this pointer shall be associated.

is strong evidence for pmk’s interpretation. You can see the point of Richard Maine’s observation.

Malcolm Cohen has written to me with a comment on this. He seems to accept that there is a contradiction in the Standard which will be addressed. It is worth pointing out his usual procedure for similar issues: was the code conforming in earlier standards (yes, for F2003) and if so, is it explicitly mentioned in, for instance, “4.3.4 Fortran 2003 compatibility” that the code is no longer conforming (it is not mentioned). We can then assume that the intention was that the code conforms to F2018 and that will be the interpretation decision.

1 Like