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

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.

Related

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

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.

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.

Automatic allocation failing when casting from integer to real(dp)

I don't know whether I'm hitting a compiler bug or missing something. I'm attempting to run the following code:
program test
implicit none
integer, parameter :: dp=kind(1.d0)
integer, allocatable :: int_mat(:,:)
integer, allocatable :: int_mat_2(:,:)
real(dp), allocatable :: real_mat(:,:)
allocate(int_mat(2,2))
int_mat = 0
int_mat_2 = int_mat
real_mat = int_mat ! Falls over here.
end program
Compiling and running with nagfor (flags: -f2003 -C=all) works as expected. Compiling and running with gfortran (flags: -std=f2003 -fcheck=all) fails at runtime with the error message:
At line 13 of file test.f90
Fortran runtime error: Array bound mismatch for dimension 1 of array 'real_mat' (1/2)
I would expect the code to succeed, as int_mat_2 and real_mat should be allocated implicitly. This seems to be happening correctly for int_mat_2 but not for real_mat.
I have tried this with various gfortran versions (5.4, 6.3, 7.0), and all have the same problem.
As found by francescalus, this was this compiler bug, which has since been fixed for more recent gfortran versions.

Type of a hardcoded argument

When I try to compile my code using gfortran 4.4.7 I get the following error message:
Error: Type mismatch in argument 'intkind8' at (1); passed INTEGER(4)
to INTEGER(8).
With ifort it does compile, unless I demand the F2003 standard, in which case a similar error is given.
My code:
program kindDummy
implicit none
call takeIntKind4And8(0,0)
contains
subroutine takeIntKind4And8(intKind4, intKind8)
implicit none
integer(kind=4), intent(in) :: intKind4
integer(kind=8), intent(in) :: intKind8
print *, 'Integer(kind4): ', intKind4
print *, 'Integer(kind8): ', intKind8
end subroutine takeIntKind4And8
end program kindDummy
I was wondering if there's an elegant way to make the compiler "turn" the first 0 into a kind=4 integer, and the second one into a kind=8?
In
call takeIntKind4And8(0,0)
both zeros have the default kind. The kind numbers are not portable, but your default one is probably 4.
To produce 0 of kind 8 use 0_8:
call takeIntKind4And8(0_4,0_8)
I recommend to stay away from using 4 and 8 directly and use integer constants like 0_ip where ip is an integer constant with the right value. See Fortran: integer*4 vs integer(4) vs integer(kind=4) for more.

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!