gfortran : check subroutine argument list (if call match definition) - fortran

I'm debugging fortran program with gfortran using -g -Og -fcheck=all
It still does not report errors, that the number and type of arguments in call differs from the definition
e.g. it pass things like this without errors:
Definition:
subroutine assemble_2c(iforce, itheory, natoms)
integer, intent(in) :: iforce
integer, intent(in) :: itheory
integer, intent(in) :: natoms
...
end subroutine
use
call assemble_2c()
also this:
subroutine assemble_2c()
...
end subroutine
use
call assemble_2c(iforce, itheory, natoms)
comming from C/C++ (Java, python... basically any other language) ... this seems to me as perhaps the most basic thing which compiler should check, so I'm really dismayed it does not.

Related

Why does f2py say that an iso_fortran_env value does not reduce to a constant expression?

I can compile the following code just fine using gfortran -c test.f90.
module math
contains
function addition(a, b) result(f)
use iso_fortran_env, only: REAL64
implicit none
real(REAL64), intent(in) :: a, b
real(REAL64) :: f
f = a + b
end function
end module
I use f2py
python -m numpy.f2py -c test.f90 -m test
and I get the following error
/tmp/tmpJLxRSe/src.linux-x86_64-2.7/test-f2pywrappers2.f90:7:16:
real(kind=real64) a
1
Error: Parameter ‘real64’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
I have verified that I can successfully use selected_real_kind(15,307), as suggested in this SO post. However, I was interested in using iso_fortran_env, if possible.
Simplest way is to just use real(8) or real*8 as long as you are using gfortran or ifort with F2PY.
Alternatively, as mentioned for example here you could possibly solve it by making a file .f2py_f2cmap with the content:
dict(real=dict(REAL64='double'))
But anyway the iso_fortran_env is then not relevant anymore. An alternative is to call the real code from a simplified fortran subroutine that has only real(8) definitions.

PGI compilation error in Fortran: "forward reference to function"

I am a little puzzled with the PGI Fortran compiler.
When I try to compiler the following simple module stored in the file named test.f90, with pgfortran 19.10 I get errors that I do not understand. While compiling with gfortran or ifort run well.
The file test.f90:
MODULE CT
IMPLICIT NONE
integer, parameter :: si = SELECTED_INT_KIND(4)
integer(kind=si), public, parameter :: strlen = 256
type, public :: CMT
integer (kind=si) :: nbTot
character(len=strlen), dimension(:), allocatable :: condi
CONTAINS
procedure :: find_line_condi
endtype CMT
CONTAINS
PURE function find_line_condi( table, cara ) result(k)
IMPLICIT NONE
class(CMT), intent(in) :: table
character(len=*), intent(in) :: cara
integer (kind=si) :: k
integer (kind=si) :: j
k=-1
do j=1,table%nbTot
if (trim(table%condi(j)) .eq. cara) then
k=j
RETURN
else if ( j == table%nbTot ) then
k=-1
RETURN
endif
enddo
end function find_line_condi
END MODULE CT
The compilation with pgfortran -c test.f90 returns me the following error message:
/opt/pgi/linux86-64-llvm/19.10/share/llvm/bin/llc: error: /opt/pgi/linux86-64-llvm/19.10/share/llvm/bin/llc: /tmp/pgfortranr2qeZBujkwvA.ll:23:77: error: invalid forward reference to function 'ct_find_line_condi_' with wrong type: expected 'i32 (i64*, i64*, i64*, i64)*' but was 'i16 (i64*, i64*, i64*, i64)*'
#ct$cmt$td$vft = global [1 x i8*] [i8* bitcast(i16 (i64*, i64*, i64*, i64)* #ct_find_line_condi_ to i8*)]
Does anyone has some ideas where this problem comes from?
This is a bug in the compiler. Consider the module
MODULE CT
IMPLICIT NONE
type CMT
CONTAINS
procedure, nopass :: find_line_condi
endtype CMT
CONTAINS
function find_line_condi()
integer(SELECTED_INT_KIND(4)) find_line_condi
find_line_condi=0
end function find_line_condi
END MODULE CT
which is quite a bit simpler than that of that question. Compiled with pgfortran 19.10 there is a similar gibberish output. It's left as an exercise to the reader/PGI support desk whether this simpler code is valid Fortran which should be accepted but I would consider the poor diagnostic to be something PGI would prefer to avoid.
However, this appears to be a weakness in the LLVM frontend of PGI: consider compiling with pgfortran -c -Mnollvm .... There are also ways to rewrite the code to attempt to work around this bug, such as changing the kind of the function result.
More widely, PGI introduced in the 2019 releases the LLVM code generator. This seems to be going through a number of teething difficulties. If you have code unexpectedly failing with PGI 2019 (which may have worked with 2018), then compiling with -Mnollvm to use the non-LLVM generator is worth a try.

Have time in a pure manner in Fortran?

I am looking for a pure way to have access to time information. I thought about intrinsic functions and subroutines of standards compiler (date_and_time,cpu_time, system_clock, ltime, ctime, ...), the format do not really matter to me. I also thought about MPI function, but it is the same as intrinsic functions, there are all impure functions.
Here is a minimal example:
elemental subroutine add(message, text)
! function add
IMPLICIT NONE
character(len=:),allocatable,intent(inout) :: message
character(len=*), intent(in) :: text
character(len=1), parameter :: nl=char(10)
character(10) :: time
! character(8) :: date
! time= 'hhmmss.sss'
call DATE_AND_TIME(time)
Message= Message//time////text//nl
end subroutine add
and I get a logical error :
Error: Subroutine call to intrinsic ‘date_and_time’ at (1) is not PURE
Thus, I am wandering if a pure way to have a time information exists, or if it is impossible to have it purely (maybe because it has to use cpu information which, for a reason unknown to me, could be thread-unsafe).
Maybe, a subquestion, could be is there a solution to force the compiler to consider date_and_time pure (or any other function of that kind)?
The answer about a pure manner to get time is no. A function that returns the current time or date, is impure because at different times it will yield different results—it refers to some global state.
There are certainly tricks to persuade the compiler that a subroutine is pure. One is to flat out lie in an interface block.
But there are consequences from lying to the compiler. It can do optimizations which are unsafe to do and the results will be undefined (most often correct anyway, but...).
module m
contains
elemental subroutine add(text)
IMPLICIT NONE
character(len=*), intent(in) :: text
character(len=1), parameter :: nl=char(10)
character(10) :: time
intrinsic date_and_time
interface
pure subroutine my_date_and_time(time)
character(10), intent(out) :: time
end subroutine
end interface
call MY_DATE_AND_TIME(time)
end subroutine add
end module
program test
use m
call add("test")
end program
subroutine my_date_and_time(time)
character(10), intent(out) :: time
call date_and_time(time)
end subroutine
Notice I had to delete your message because that was absolutely incompatible with elemental.

Calling BLAS functions

Here is a simple program
PROGRAM MAIN
implicit none
integer, PARAMETER :: N=10
real*8 :: A(N)
real*8 :: x=0.1D0
integer :: i=1
Do i=1,N
A(i)=i
end do
call dscal(N,x, A, 1)
x=dasum(N,A,1)
END PROGRAM MAIN
I compile with the command
gfortran test.f90 -o test -O1 -I /usr/include/ -L /usr/lib -lblas
While I have no problem calling the subroutine dscal I get the following error for the function dasum
test.f90:15.2:
x=dasum(N,A,1)
1
Error: Function 'dasum' at (1) has no IMPLICIT type
Should I include a certain file to define the BLAS functions?
For functions, you need to manually specify the return value (and if you are feeling posh, optionally an external):
real*8,external :: dasum
Additionally, please don't use real*8. It is not Standard-conforming, not portable and quite confusing. Instead use the kind parameter to define the precision, e.g.:
real(kind=kind(1.d0))
or the like. If you can use the ISO_Fortran_env module, use its constants REAL32 and REAL64.

How to force fortran compiler to generate an error in case of violation "intent(in)" by subroutine with omitted intent

This question is connected to my previous question: How to force compiler to interpret omitted intent as intent(inout) . It appears impossible to interpret omitted intent as intent(inout), so problem of violation of intent(in) is still exists.
The same example:
module test
implicit none
contains
subroutine fun1(x)
real(8), intent(in)::x
call fun2(x)
end subroutine
subroutine fun2(x)
real(8) :: x
x = 10
end subroutine
end module
This code can be compiled without any errors/warnings by gfortran and ifort. So my questions is:
How to force fortran compiler to generate an error when intent(in) variable is passed to subroutine with omitted intent ( but with declared interface)?
As IanH said you need a processor (i.e. compiler) that can pick this up for you. For instance the NAG compiler does (disclaimer - I work for NAG) if you give it the right flags. I modified your code a very little to make it portable and added a driver to show this:
$ cat t.f90
module test
implicit none
Integer, Parameter :: wp = Selected_real_kind( 12, 70 )
contains
subroutine fun1(x)
real(wp), intent(in)::x
call fun2(x)
end subroutine
subroutine fun2(x)
real(wp) :: x
x = 10
end subroutine
end module
Program test_test
Use test
Implicit None
Real( wp ) :: x
x = 5.0_wp
Call fun1( x )
End Program test_test
$ nagfor t.f90
NAG Fortran Compiler Release 5.3.1 pre-release(904)
[NAG Fortran Compiler normal termination]
$ ./a.out
$ nagfor -C=all -C=undefined t.f90
NAG Fortran Compiler Release 5.3.1 pre-release(904)
[NAG Fortran Compiler normal termination]
$ ./a.out
Runtime Error: t.f90, line 15: Dummy argument X is associated with an expression - cannot assign
Program terminated by fatal error
Aborted (core dumped)
$
So search the flags, there may be something to help - if not complain to whoever supplies the compiler!