Segmentation fault when using abstract interface with assumed shape

The code below compiles correctly, but produces a segmentation fault when run. The problem seems to be the abstract interface with assumed shape arrays: sub fails, but sub2 works. Other compilers (gfortran, ifort, nagfor) work as expected.

nvfortran 23.1-0 64-bit target on x86-64 Linux -tp skylake-avx512 
NVIDIA Compilers and Tools
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.  All rights reserved.
module mymod

  use, intrinsic :: iso_fortran_env, only: real64

  implicit none
  private

  public :: mysub, mysub2

  abstract interface
    subroutine mysub(A, B)
      import :: real64
      complex(kind=real64), intent(in) :: A(:,:)
      complex(kind=real64), intent(out) :: B(:,:)
    end subroutine mysub
    subroutine mysub2(A, B, n)
      import :: real64
      integer, intent(in) :: n
      complex(kind=real64), intent(in) :: A(n,n)
      complex(kind=real64), intent(out) :: B(n,n)
    end subroutine mysub2
  end interface

end module mymod

subroutine sub(A, B)

  use, intrinsic :: iso_fortran_env, only: real64

  implicit none
  complex(kind=real64), intent(in) :: A(:,:)
  complex(kind=real64), intent(out) :: B(:,:)

  B = A

end subroutine sub

subroutine sub2(A, B, n)

  use, intrinsic :: iso_fortran_env, only: real64

  implicit none
  integer, intent(in) :: n
  complex(kind=real64), intent(in) :: A(n,n)
  complex(kind=real64), intent(out) :: B(n,n)

  B = A

end subroutine sub2

program prog

  use, intrinsic :: iso_fortran_env, only: real64
  use mymod, only: mysub, mysub2

  implicit none
  complex(kind=real64) :: A(3,3), B(3,3)
  procedure(mysub) :: sub
  procedure(mysub2) :: sub2

  A(:,:) = (1.0_real64, 2.0_real64)
  B(:,:) = (0.0_real64, 0.0_real64)

  ! "sub" fails, but "sub2" works!
  call sub(A, B)
  !call sub2(A, B, 3)

  write(6,*) B

end program prog

Thanks for the report Jellby. I talked with one of our Fortran engineers and he agrees that it’s likely a compiler issue. Hence I filed a problem report, TPR #33040, and engineering will investigate.

He did suggest using submodules might be a better option for you, or at least as a work around:

% cat test2.f90
module mymod

  use, intrinsic :: iso_fortran_env, only: real64

  implicit none
  private

  public :: sub, sub2

  interface
     module subroutine sub(A, B)
       import :: real64
       complex(kind=real64), intent(in) :: A(:,:)
       complex(kind=real64), intent(out) :: B(:,:)
     end subroutine
     module subroutine sub2(A, B, n)
       import :: real64
       integer, intent(in) :: n
       complex(kind=real64), intent(in) :: A(n,n)
       complex(kind=real64), intent(out) :: B(n,n)
     end subroutine
  end interface

end module mymod

submodule(mymod) submod
contains
  module subroutine sub(A, B)

    use, intrinsic :: iso_fortran_env, only: real64

    implicit none
    complex(kind=real64), intent(in) :: A(:,:)
    complex(kind=real64), intent(out) :: B(:,:)

    B = A

  end subroutine sub

  module subroutine sub2(A, B, n)

    use, intrinsic :: iso_fortran_env, only: real64

    implicit none
    integer, intent(in) :: n
    complex(kind=real64), intent(in) :: A(n,n)
    complex(kind=real64), intent(out) :: B(n,n)

    B = A

  end subroutine sub2
end submodule submod

program prog

  use, intrinsic :: iso_fortran_env, only: real64
  use mymod, only: sub, sub2

  implicit none
  complex(kind=real64) :: A(3,3), B(3,3)

  A(:,:) = (1.0_real64, 2.0_real64)
  B(:,:) = (0.0_real64, 0.0_real64)

  ! "sub" fails, but "sub2" works!
  call sub(A, B)
  !call sub2(A, B, 3)

  write(6,*) B

end program prog
% nvfortran test2.f90; a.out
 (1.000000000000000,2.000000000000000)  (1.000000000000000,2.000000000000000)
 (1.000000000000000,2.000000000000000)  (1.000000000000000,2.000000000000000)
 (1.000000000000000,2.000000000000000)  (1.000000000000000,2.000000000000000)
 (1.000000000000000,2.000000000000000)  (1.000000000000000,2.000000000000000)
 (1.000000000000000,2.000000000000000)

Here is another minimal program reproducing the same segmentation fault error. One can get it working if the explicit pointer defined with the same abstract interface is used instead of direct subroutine call.

subroutine sub(B)

  integer :: B(:)

  B = 1

end subroutine sub

program prog

  abstract interface
   subroutine mysub(B)
     integer :: B(:)
   end subroutine mysub
  end interface

  integer :: B(3)
  procedure(mysub) :: sub
  procedure(mysub), pointer :: p

  p => sub
  ! explicit pointer p works
  call p(B)
  write(6,*) B
  ! "sub" itself fails
  call sub(B)
  write(6,*) B

end program prog

The same trick works with the code of @Jellby. I guess it is the point that the compiler does not create the pointer (or does ill-defined one) automatically when using the abstract interface.

Hope it helps if the problem is not solved yet.