Выброс ошибки, если какой-либо интерфейс процедуры не определен явно или в модуле в Fortran 90+

В статье Ошибки в Fortran 90 программ, которые могут вас удивить

Существует следующий раздел:

Опасность вызова подпрограмм стиля Fortran 90

      program main
      real, dimension(5) :: x

      x = 0.
! THIS IS WRONG
      call incb(x)
      print *, x

      end program main

      subroutine incb(a)
! this is a fortran90 style subroutine
      real, dimension(:) :: a
      a = a + 1.
      end subroutine incb

Объяснение Подпрограмма incb использует принятую форму стиля Fortran 90 array (содержащий размерность (:)). Такие процедуры должны либо находиться в модулем или иметь явный интерфейс там, где они используются. В этом Например, никто не был прав.

Одним из правильных способов вызова таких процедур является использование явного интерфейс следующим образом:

      program main
      real, dimension(5) :: x

! THIS IS THE RIGHT WAY
      interface
         subroutine incb(a)
           real, dimension(:) :: a
         end subroutine incb
      end interface

      x = 0.
      call incb(x)
      print *, x

      end program main

      subroutine incb(a)
! this is a fortran90 style subroutine
      real, dimension(:) :: a
      a = a + 1.
      end subroutine incb

Если подпрограмма в интерфейсе модуля генерируется автоматически и не нужно явно писать.

! THIS IS ANOTHER RIGHT WAY
      module inc
      contains
      subroutine incb(a)
! this is a fortran90 style subroutine
      real, dimension(:) :: a
      a = a + 1.
      end subroutine incb
      end module inc

      program main
      use inc
      real, dimension(5) :: x

      x = 0.
      call incb(x)
      print *, x

      end program main

Если используются интерфейсы, интерфейс ДОЛЖЕН соответствовать фактической функции.

Итак, продолжая мой вопрос, есть ли опция в gfortran или других компиляторах для предотвращения компиляции, если есть вызов процедуры, интерфейс которой не определен явно (или определен в модуле)?

Если нет, не должна ли это быть функцией?

Ответ 1

Для gfortran существует опция компиляции -Wimplicit-interface:

-Wimplicit-процедура
    Предупреждать, если вызывается процедура, которая не имеет явного интерфейса и не объявлена ​​как EXTERNAL.

Это можно связать с -Werror, чтобы рассматривать это как ошибку.

При компиляции этого (с gfortran 4.8.2)

  call heffalump(1)
end

видно, что

call heffalump (1)
                   1
Предупреждение: процедура "heffalump" вызывается с неявным интерфейсом в (1)

Обратите внимание, однако, что, хотя это может быть полезным тестом для "глупых ошибок" в недавно разработанном современном коде, все может быть совершенно правильным и все еще терпеть неудачу в этом тесте. См. Также комментарий Владимира Ф. к этому ответу.

Конечно, компилятор в большинстве случаев не может определить, требует ли процедура явного интерфейса. См. этот ответ для параметров, позволяющих компилятору сделать небольшую дополнительную работу в этом отношении.

Ответ 2

У компиляторов есть это. Ifort имеет -warn interfaces, включенный в -warn, gfortran имеет эту проверку в -Wall.

interf.f90:6.15:

      call incb(x)
               1
Error: Procedure 'incb' at (1) with assumed-shape dummy argument 'a' must have an explicit interface

У компилятора будет проблема с этим, если они будут находиться в разных файлах. Некоторые найдут его, некоторые не будут.

> gfortran incb.f90 interf.f90 -Wall
> ifort incb.f90 interf.f90 -warn
interf.f90(6): error #7978: Required interface for passing assumed shape array is missing from original source   [X]
      call incb(x)

----------------^
compilation aborted for interf.f90 (code 1)

Как пишет @francesalus, вы можете форсировать предупреждения для неявных интерфейсов -Wimplicit-interface. Это, однако, делает что-то другое. Он предупреждает для КАЖДОЙ процедуры с неявным интерфейсом, даже если он соответствует стандарту.

Если вы подключаете его с помощью -Werror, вам придется написать интерфейс для каждой процедуры MPI, которая работает с буферами, в каждую используемую вами библиотеку. Я использую его, но мой код строго в модулях, и мне действительно приходилось писать интерфейсы для каждой используемой мной процедуры MPI, которая отправляет или получает некоторый буфер. Для каждого типа буфера вам нужен отдельный интерфейс (по крайней мере, в текущем Fortran 2008).

Хуже того, некоторые реализации MPI предоставляют явные интерфейсы для определенных процедур, а некоторые - нет. Как только вы приложите усилия для объявления интерфейсов для одной версии библиотеки MPI, другой начнет жаловаться, что интерфейс уже определен и отличается. (Фактическая история из траншей.)