RECURSIVE vs PURE and ELEMENTAL
Walter Spector
w6ws@earthlink.net
Sat Aug 4 03:22:00 GMT 2007
Gfortraners,
Gfortran, at least the version I am using, currently allows PURE and
ELEMENTAL procedures to call themselves, even without declaring them
to be RECURSIVE. The -pedantic option does not detect this extension
(if indeed you are supporting it as an extension).
Technically, by F95 and F2003, PURE procedures can also be declared
RECURSIVE and thereby allowed to call themselves:
PURE RECURSIVE MyProc (...)
However, for some reason unknown to me, ELEMENTAL procedures are not
allowed to also be declared RECURSIVE.
In summary, the following table shows what the Standards (95 and 2003)
allow, and what gfortran currently does:
Procedure f95/f2003 Gfortran
attributes allow allows
-------------- -------- --------
(default) No recursion Recursion*
RECURSIVE Recursion Recursion
PURE No recursion Recursion*
PURE RECURSIVE/ Recursion Recursion
RECURSIVE PURE
ELEMENTAL No recursion Recursion*
ELEMENTAL RECURSIVE/ Not allowed Not allowed
RECURSIVE ELEMENTAL
* - -pedantic does not detect this.
Both the Intel compiler and the IRIX MIPSpro compiler detect the illegal
cases and refuse to compile them. I am not opposed to gfortran continuing
to support the cases. Your call. However I do think the -pedantic option
should report them.
Appended is a small test program that I have been using to experiment
with these attributes.
Walter Spector
(w6ws@earthlink.net)
--------------------------------------------------------------------------------
module recur_subs
implicit none
contains
elemental function factorial (i) result (r)
integer, intent(in) :: i
integer :: r
r = 0
if (i < 1) return
r = factorial_inner (i, i-1)
end function
elemental function factorial_inner (val, next) result (r)
integer, intent(in) :: val
integer, intent(in) :: next
integer :: r
if (next < 2) then
r = val
return
end if
r = factorial_inner (val * next, next - 1)
end function
end module
program recur_test
use recur_subs
implicit none
integer, allocatable :: vals(:), results(:)
integer :: i
call init ()
results = factorial (vals)
print '(2i14)', (vals(i), results(i), i=1, size (vals))
contains
subroutine init ()
character(128) :: argstr
integer :: argstr_l
integer :: nargs, ioerr
nargs = command_argument_count ()
allocate (vals(nargs), results(nargs))
do, i=1, nargs
call get_command_argument (i, value=argstr, length=argstr_l, status=ioerr)
call assert_zr (ioerr, 'get_command_argument error')
read (argstr(:argstr_l), '(i14)', iostat=ioerr) vals(i)
call assert_zr (ioerr, argstr(:argstr_l) // ': illegal numeric value')
end do
end subroutine
subroutine assert_zr (i, str)
integer, intent(in) :: i
character(*), intent(in) :: str
if (i == 0) return
print *, str
stop
end subroutine
end program
More information about the Fortran
mailing list