ecmwf-ifs / loki

Freely programmable source-to-source translation for Fortran

Home Page:https://sites.ecmwf.int/docs/loki/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EXTERNAL (procedures) possibly trigger assertion in fgen backend

MichaelSt98 opened this issue · comments

e.g., bug.F90

SUBROUTINE DRIVER
        real :: x
        external x
END SUBROUTINE DRIVER

executing loki-transform.py convert -m idem --frontend fp --path bug --config bug/config.config -out out

with config file

[default]
mode = "idem"
role = "kernel"

[[routine]]

name = "driver"
role = "driver"

triggers assertion in the backend:

  File "loki/loki/backend/fgen.py", line 411, in visit_ProcedureDeclaration
    assert all(t.dtype.is_function for t in types) or all(not t.dtype.is_function for t in types)
  File "loki/loki/backend/fgen.py", line 411, in <genexpr>
    assert all(t.dtype.is_function for t in types) or all(not t.dtype.is_function for t in types)

changing

--- a/loki/backend/fgen.py
+++ b/loki/backend/fgen.py
@@ -398,14 +398,14 @@ class FortranCodegen(Stringifier):
         # TODO: We can't fully compare procedure types, yet, but we can make at least sure
         # names match and other declared attributes are compatible
         ignore = ['dtype', 'shape', 'dimensions', 'symbols', 'source', 'initial']
-        assert all(isinstance(t.dtype, ProcedureType) for t in types)
+        # assert all(isinstance(t.dtype, ProcedureType) for t in types)
         assert all(t.compare(types[0], ignore=ignore) for t in types)
         if isinstance(o.interface, DataType):
             assert all(t.dtype.return_type.dtype == o.interface for t in types)
         elif o.interface is not None:
             assert all(t.dtype.name == o.interface for t in types)
 
-        if o.external:
+        if o.external and not isinstance(types[0].dtype, BasicType):
             # This is an EXTERNAL statement (i.e., a kind of forward declaration)
             assert o.interface is None
             assert all(t.dtype.is_function for t in types) or all(not t.dtype.is_function for t in types)

allows for successful transformation.
However, the generated output is not valid:

SUBROUTINE DRIVER ()
  REAL, EXTERNAL :: x
  PROCEDURE, REAL, EXTERNAL :: x
END SUBROUTINE DRIVER

as gfortran -c ...

gives

    3 |   PROCEDURE, REAL, EXTERNAL :: x
      |   1
Error: Unclassifiable statement at (1)