Tool to warn about intent(out) arguments not set

Motivated by a current thread, and extending some code in the Pure-Fortran project, I created using Codex

It handles not only scalar intent(out) arguments but array arguments where some values may not be set. For example, for the code

module m
implicit none
contains
subroutine sub(x,y1,y2,z,a,b)
real, intent(in) :: x
real, intent(out) :: y1, y2, z(3), a(:), b(:)
y1 = x
z(1) = x
if (size(a) > 0) a(1) = x
if (size(b) >= 2) b(1:2) = x
end subroutine sub
end module m

program main
use m
implicit none
real :: x = 10.0, y1, y2, z(3), a(4)
real, allocatable :: b(:)
allocate (b(2*3))
call sub(x, y1, y2, z, a, b)
print*,y1,y2
print*,z
print*,"a =", a
print*,"b =", b
end program main

python xintent.py xintent_out.f90 --warn-unset-intent-out says

Summary of 0 functions and 4 subroutines with declared intent(out) arguments not wholly set in 1 source file:
xintent_out.f90 subroutine sub:a [only element 1 may be set; other elements may be unset]
xintent_out.f90 subroutine sub:b [only section 1:2 may be set; other elements may be unset]
xintent_out.f90 subroutine sub:y2
xintent_out.f90 subroutine sub:z [indices 2:3 not set]

There are probably larger procedures for which it fails. (If you encounter one and want a fix, please create an issue in the repo.) Codex is good at creating static analysis tools in Python.

2 Likes

The tool can now annotate procedure calls with comments saying what the argument intents are, with

python xintent.py foo.f90 --annotate-calls

giving code such as

module la_blas_d
implicit none
integer, parameter :: dp = kind(1.0d0), ilp = kind(0), &
lk = kind(.true.)

 contains

 pure subroutine la_dgemm(transa,transb,m,n,k,alpha,a,lda,b,ldb,beta,c,ldc)
    ! -- reference blas level3 routine --
    ! -- reference blas is a software package provided by univ. of tennessee,    --
    ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..--
       ! Scalar Arguments
       real(dp),intent(in) :: alpha,beta
       integer(ilp),intent(in) :: k,lda,ldb,ldc,m,n
       character,intent(in) :: transa,transb
       ! Array Arguments
       real(dp),intent(in) :: a(lda,*),b(ldb,*)
       real(dp),intent(inout) :: c(ldc,*)
    ! =====================================================================
       ! Intrinsic Functions
       intrinsic :: max
       ! Local Scalars
       real(dp) :: temp
       integer(ilp) :: i,info,j,l,nrowa,nrowb
       logical(lk) :: nota,notb
 end subroutine la_dgemm

end module la_blas_d

program demo_dgemm
! multiply c = alphaab + beta*c using blas dgemm
use la_blas_d
use, intrinsic :: iso_fortran_env, only: real64
implicit none

! integer, parameter :: dp = real64
integer :: m, n, k, lda, ldb, ldc
real(kind=dp) :: alpha, beta
real(kind=dp), allocatable :: a(:,:), b(:,:), c(:,


m = 2
k = 3
n = 2
lda = m
ldb = k
ldc = m

alpha = 1.0_dp
beta = 0.0_dp

allocate(a(m,k), b(k,n), c(m,n))

a = reshape([ &
1.0_dp, 2.0_dp, &
3.0_dp, 4.0_dp, &
5.0_dp, 6.0_dp  &
], shape(a))

b = reshape([ &
10.0_dp, 20.0_dp, 30.0_dp, &
40.0_dp, 50.0_dp, 60.0_dp  &
], shape(b))

c = 0.0_dp

call la_dgemm(ā€˜n’, ā€˜n’, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
! intent(in): ā€˜n’, ā€˜n’, m, n, k, alpha, a, lda, b, ldb, beta, ldc
! intent(inout): c

print *, ā€˜a =’
call print_matrix(a)
! intent(in): a

print *, ā€˜b =’
call print_matrix(b)
! intent(in): b

print , 'c = ab =’
call print_matrix(c)
! intent(in): c

contains

subroutine print_matrix(x)
! print a 2d real matrix
real(kind=dp), intent(in) :: x(:,

integer :: i

do i = 1, size(x,1)
print ā€˜(100f10.3)’, x(i,

end do
end subroutine print_matrix

end program demo_dgemm

It would be easy to only give comments for intent(out) and intent(in out) arguments.