Combining submodules, procedure arguments and polymorphic types

308 views Asked by At

I am currently trying to split my code into modules and submodules. I have a number of procedures which take procedures as arguments, and in some cases the arguments of those procedure arguments are polymorphic. When splitting these procedures into submodules my code no longer compiles.

As a minimum working example, I have a module file m.f90:

module m
  implicit none
  
  ! Interface to `foo`, which simply calls `lambda(input)`.
  interface foo
    module subroutine foo(input,lambda)
      implicit none
      
      class(*), intent(in)  :: input
      procedure(TestLambda) :: lambda
    end subroutine
  end interface
  
  ! Interface to `bar`, which simply calls `lambda(input)`
  interface bar
    module subroutine bar(input,lambda)
      implicit none
      
      class(*), intent(in)  :: input
      procedure(TestLambda) :: lambda
    end subroutine
  end interface
  
  ! Interface defining the `lambda` arguments of `foo` and `bar`.
  interface TestLambda
    subroutine TestLambda(input)
      implicit none
      
      class(*), intent(in) :: input
    end subroutine
  end interface

end module

and a submodule file m_sub.f90:

submodule (m) m_sub
contains

  ! Implementation of `foo`.
  module subroutine foo(input,lambda)
    implicit none

    class(*), intent(in)  :: input
    procedure(TestLambda) :: lambda
    
    call lambda(input)
  end subroutine
  
  ! Implementation of `bar`.
  ! This is identical to `foo`, except that the interface is implicit.
  module procedure bar
    call lambda(input)
  end procedure

end submodule

and, for completeness, a program file main.f90:

program test
  use m
  implicit none
  
  write(*,*) 'Hello, World!'
  call test_lambda(1)
  call foo(1, test_lambda)
  call bar(1, test_lambda)
contains
  subroutine test_lambda(input)
    implicit none
    
    class(*), intent(in) :: input
    
    write(*,*) 'Hello, World!'
  end subroutine
end program

I am compiling this using CMake, with a CMakeLists.txt file:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
enable_language(Fortran)
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/mod/)

if("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "GNU")
  set(CMAKE_Fortran_FLAGS "-W -Wall -Wextra -pedantic -fcheck=all -std=f2008")
elseif("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Intel")
  set(CMAKE_Fortran_FLAGS "-stand f08 -warn all")
endif()

project(test)
add_executable(test main.f90 m.f90 m_sub.f90)

If I compile with gfortran 10.1.0 then foo compiles and runs fine on its own, but trying to compile bar gives the error

   26 |       call lambda(input)
      |                  1
Error: Explicit interface required for polymorphic argument at (1)

If I instead compile with ifort 2021.1 I get the compile-time warning (for both foo and bar)

 warning #8889: Explicit declaration of the EXTERNAL attribute is required.   [LAMBDA]
      call lambda(input)
-----------^

And then the linker error (for both foo and bar)

m_sub.f90.o: In function `m_mp_foo_':
undefined reference to `lambda_'

As far as I can tell, what I'm doing is valid Fortran. So am I seeing compiler bugs / unimplemented features? Or am I trying to do something which isn't allowed by the standard?

0

There are 0 answers