I want to detect from inside a subroutine that a dummy argument passed with intent(in)
is actually a null pointer:
program testPTR
implicit none
integer, target :: ii
integer, pointer :: iPtr
iPtr => ii
iPtr = 2
print *, "passing ii"
call pointer_detect(ii)
print *, "passing iPtr"
call pointer_detect(iPtr)
iPtr => null()
print *, "passing iPtr => null()"
call pointer_detect(iPtr)
contains
subroutine pointer_detect(iVal)
implicit none
integer, intent(in), target :: iVal
integer, pointer :: iPtr
character(len = *), parameter :: sub_name = 'pointer_detect'
iPtr => iVal
if (associated(iPtr)) then
print *, "Pointer associated. Val=", iVal, ", iPtr = ", iPtr
else
print *, "Pointer not associated. Val=", iVal, ", iPtr = ", iPtr
endif
end subroutine pointer_detect
end program
To my surprise it works with gfortran-9 and gfortran-12. However I have got a couple of questions:
$ gfortan test.f90
$ ./a.out && echo ok
passing ii
Pointer associated. Val= 2 , iPtr = 2
passing iPtr
Pointer associated. Val= 2 , iPtr = 2
passing iPtr => null()
Pointer not associated. Val= 0 , iPtr = 0
ok
$
Any ideas? Thank you!
The fragment
iPtr => null()
print *, "passing iPtr => null()"
call pointer_detect(iPtr)
violates the Fortran standard and makes your program invalid (Fortran 2008, 25.5.2.3):
Except in references to intrinsic inquiry functions, a pointer actual argument that corresponds to a nonoptional nonpointer dummy argument shall be pointer associated with a target.
The dummy argument of the non-intrinsic procedure is neither optional, nor a pointer.
Responsibility for avoiding this problem is entirely the programmer's and the compiler has no duty to detect this broken code for you.
A compiler may well be able to detect such bugs, if asked, however (usually at run time):
At line 19 of file brokenpointer.f90
Fortran runtime error: Pointer actual argument 'iptr' is not associated
being the output when using gfortran and the compile option -fcheck=pointer
, or
forrtl: severe (408): fort: (7): Attempt to use pointer IPTR when it is not associated with a target
with ifort's -check pointers
.
The programmer cannot reliably do similar checks within the procedure itself, because a Fortran compiler is under no obligation to respect the programmer who breaks the rules in this way.
Looking at the procedure's efforts here, for example:
iPtr => iVal
if (associated(iPtr)) then
iVal
is not a pointer, so iPtr
becomes associated with that variable in that pointer assignment. The compiler is allowed to assume you haven't broken the rules of Fortran, so iptr
is associated and that test condition is always true. There is no valid Fortran program in which that test condition can resolve to false.
However, not all hope is lost. The text from the standard I quote says something other than "nonpointer": it says "nonoptional". If iVal
is instead optional use PRESENT()
:
subroutine pointer_detect(iVal)
implicit none
integer, intent(in), optional :: iVal
character(len = *), parameter :: sub_name = 'pointer_detect'
if (present(iVal)) then
print *, "Actual argument pointer was associated. Val=", iVal
else
print *, "Actual argument pointer was not associated."
endif
end subroutine pointer_detect
A nonpointer, nonallocatable, optional dummy argument will be treated as not present if associated with a disassociated pointer actual argument.
Note, however, that this won't help you if iPtr
is of undefined association status. Nothing will.