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?