module funcs
implicit none
contains
pure function str(array) result(res)
character(len=:), allocatable :: res
character(len=1), intent(in) :: array(:)
integer :: i, L
L = size(array)
allocate(character(len=L) :: res)
do i=1,L
res(i:i) = array(i)
end do
end function str
subroutine assert_true(var1)
logical, intent(in) :: var1
write(*,*) var1, .true., var1 .eqv. .true.
end subroutine assert_true
subroutine test_split()
call assert_true(str(['o','n','e']) == 'one')
end subroutine
end module funcs
program test
use funcs, only: test_split
implicit none
call test_split()
end program test
Compiled with:
$ nvfortran --version
nvfortran 21.7-0 64-bit target on x86-64 Linux -tp skylake
NVIDIA Compilers and Tools
Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
$ nvfortran -i8 test.f90 && ./a.out
T T F
That is printing var, .true., and var .eqv. .true.. Compiling without -i8 gives the right result (T T T).
I was able to recreate the issue and have filed TPR #30470.
As best as I can tell, it looks like we’re not promoting the kind value of the logical argument when the logic test is done within the argument. Hence var1 is being passed in as kind 4 but evaluated as kind 8.
For example, if I just pass in “.true. .eqv. .true.”, I see a kind mismatch error:
% cat test2.F90
module funcs
implicit none
contains
subroutine assert_true(var1)
logical, intent(in) :: var1
write(*,*) var1, .true., var1 .eqv. .true.
end subroutine assert_true
subroutine test_split()
character(len=3) :: str1 = "one"
logical :: var1
call assert_true(str1 == 'one')
#ifdef KIND_ERR
! This gives a kind mismatch if "-i8" is used
call assert_true(.true. .eqv. .true.)
#endif
var1 = str1 == 'one'
call assert_true(var1)
end subroutine
end module funcs
program test
use funcs, only: test_split
implicit none
call test_split()
end program test
% nvfortran test2.F90 -i8 -DKIND_ERR
NVFORTRAN-S-0450-Argument number 1 to assert_true: kind mismatch (test2.F90: 17)
0 inform, 0 warnings, 1 severes, 0 fatal for test_split
% nvfortran test2.F90 -i8 ; a.out
T T F
T T T
% nvfortran test2.F90 -i4 ; a.out
T T T
T T T
The work around would be to not evaluate the logic expression as part of the arguments, but rather set it to a temp variable and then pass the variable to assert_true.
% cat test.f90
module funcs
implicit none
contains
pure function str(array) result(res)
character(len=:), allocatable :: res
character(len=1), intent(in) :: array(:)
integer(8) :: i, L
L = size(array)
allocate(character(len=L) :: res)
do i=1,L
res(i:i) = array(i)
end do
end function str
subroutine assert_true(var1)
logical, intent(in) :: var1
write(*,*) var1, .true., var1 .eqv. .true.
end subroutine assert_true
subroutine test_split()
logical :: var
var = str(['o','n','e']) == 'one'
call assert_true(var)
! call assert_true(str(['o','n','e']) == 'one')
end subroutine
end module funcs
program test
use funcs, only: test_split
implicit none
call test_split()
end program test
% nvfortran test.f90 -i8 ; a.out
T T T