Search code examples
visual-studio-2017fortrancontainssubroutineintel-oneapi

Can a subroutine be contained in a subroutine (not in a program) in Fortran?


I have to deal with an old piece of software written in Fortran (mainly written in the 70's and badly maintained up to 3 years ago).

I am trying to get it compiled with VS2017 and the Intel oneAPI compiler (Fortran Compiler Classic 2021.3.0) for 64-bits architectures.

In the process of updating one of its modules, I convinced myself that the compiler does not support what I have learned to be called "host association" between subroutines (via CONTAINS statement). None of the symbols defined in a containing subroutine seems to be visible in the contained subroutine (if I use IMPLICIT NONE in the contained subroutine the compiler tells me that I need to declare all of them while if I don't, the compilers gets the declarations very wrong and not matching with the declarations in the containing subroutine. Lots of misleading error messages are printed).

Can somebody of you confirm that this is the case or provide the compiler options to enable this feature that clearly was allowed in the past by some compilers? If needed I will post the source code (I am not posting it immediately because I think this could be a very naive question for a Fortran expert, I am instead a total novice).

Sincerely,

HERE I COMPLEMENT THE ORIGINAL POST AS REQUESTED IN THE COMMENTS

Original code:

Subroutine LoadUserLibs(TypesInDeck,*) 

... OMITTED COMMENTS ...

! This routine is only used in the multi-DLL configuration (otherwise empty routine)

!dec$ if defined (TRNSYS_MULTI_DLL)

 Use DFWIN
 Use DFLIB
 !Use KERNEL32
 Use TrnsysConstants
 Use TrnsysFunctions
 Use TrnsysData, Only: steamMethod,isNISTSteamFound

! Force explicit variable declaration
 Implicit None
! Local variable declarations
 Type(T_WIN32_FIND_DATA):: WFD
 Character (len=maxPathLength) UserDir,FoundListStr,SearchListStr
 Character (len=maxMessageLength) msgString
 Integer :: libFile, j, k
 Logical :: bSt
 Character (len=12) jStr,TypeNum,numDLLsStr
 Character (len=20) routineName
 Integer luw !listing file logical unit number
 Integer (kind=8) ExistTest !declares an integer to temporarily contain a pointer
 Integer i !not used but must be delcared as part of a POINTER declaration.
 Integer (kind=8) LibHandles(100) !declares an array where handles to loaded libraries are stored.
 Integer LibCount !a counter variable used to keep track of how many dlls have been loaded
 Integer TypeCount !a counter variable used to count how many Types were found in a given dll.
 Integer TypesInDeck(nMaxUnits) !an array containing a list of Types that are in the deck being run.
 Integer TotalTypes/0/ !the total number of Types in the deck being run (no duplicates)
 Integer TypesListed/0/ !a variable used to count how many of the Types that were found, have been listed so far.
 Integer, Allocatable :: SearchList(:,:) !an array of Type numbers to look for in dlls.
 Integer, Allocatable :: FoundList(:)
 Logical :: isType155InDeck = .false., isType155DllFound = .false.
! Common black definitions
 Integer(INT_PTR_KIND()) paa(nMaxTypes)  !declares an integer array that will contain pointer addresses to the Types
 Integer(INT_PTR_KIND()) saa  !declares an integer that will contain a pointer address of the NIST steam routines.
 Common /USRDLLS/ paa,saa
! Pointer definitions
 Pointer (p,i)

... OMITTED CODE ...

!dec$ else
   ! Single-DLL configuration: empty routine
!dec$ endif

 Return

Contains

Subroutine LoadTypesFromDll()

... OMITTED CODE ...

End Subroutine LoadTypesFromDll

End Subroutine LoadUserLibs

Errors I received compiling the original code:

Severity    Code    Description Project File    Line    Suppression State
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   276 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   284 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   303 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   309 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   314 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   315 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   317 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.   [CFILENAME]       C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   302 
Error       error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.   [CFILENAME]       C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   308 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   276 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   284 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   284 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   303 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   309 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   314 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   315 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   315 
Error       error #6362: The data types of the argument(s) are invalid.   [TRIM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   317 
Error       error #6410: This name has not been declared as an array or a function.   [FOUNDLIST]       C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   291 
Error       error #6410: This name has not been declared as an array or a function.   [LIBHANDLES]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   268 
Error       error #6423: This name has already been used as an external function name.   [PAA]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   289 
Error       error #6423: This name has already been used as an external function name.   [SEARCHLIST]       C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   292 
Error       error #6460: This is not a component name that is defined in the encompassing structure.   [CFILENAME]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   283 
Error       error #6514: Substring or array slice notation requires CHARACTER type or array.   [CFILENAME]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   302 
Error       error #6514: Substring or array slice notation requires CHARACTER type or array.   [CFILENAME]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   308 
Error       error #6514: Substring or array slice notation requires CHARACTER type or array.   [FOUNDLIST]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   321 
Error       error #6514: Substring or array slice notation requires CHARACTER type or array.   [TYPENUM]        C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   284 
Error       error #6515: This function, which is specified as the left side of an assignment statement, is invalid.   [PAA]     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   289 
Error       error #6515: This function, which is specified as the left side of an assignment statement, is invalid.   [SEARCHLIST]      C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   292 
Error       error #6535: This variable or component must be of a derived or structure type.   [WFD]     C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90   283 


Solution

  • Internal procedures (following a CONTAINS) can see all entities declared in the "host scope" (before the CONTAINS), and can see other internal procedures, but cannot see entities declared within other internal procedures. Host association goes up the tree only. For example:

    subroutine outer
    integer :: X
    ...
    contains
    subroutine innerA
    real :: A
    end subroutine innerA
    subroutine innerB
    real :: B
    end subroutine innerB
    end subroutine outer
    

    Subroutine outer can see explicit interfaces for innerA and innerB. innerA and innerB can see explicit interfaces for each other and variable X, but innerA cannot see innerB's variable B and innerB cannot see innerA's variable A.

    I am skeptical that the behavior you describe was supported by other compilers. Given that you say it was written in the 70s, it could not have used modules, which started with Fortran 90. My guess is that your "updating one of the modules" introduced errors.