NVFORTRAN: Wrong result: "var" is true but "var .eqv. .true." is false?

This file:

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).

Thanks Jellby

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

-Mat