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