Search code examples
fortranfortran90gfortranfortran77fortran95

Convert FORTRAN DEC UNION/MAP extensions to anything else


Edit: Gfortran 6 now supports these extensions :)

I have some old f77 code that extensively uses UNIONs and MAPs. I need to compile this using gfortran, which does not support these extensions. I have figured out how to convert all non-supported extensions except for these and I am at a loss. I have had several thoughts on possible approaches, but haven't been able to successfully implement anything. I need for the existing UDTs to be accessed in the same way that they currently are; I can reimplement the UDTs but their interfaces must not change.

Example of what I have:

TYPE TEST
  UNION
    MAP
      INTEGER*4 test1
      INTEGER*4 test2
    END MAP
    MAP
      INTEGER*8 test3
    END MAP
  END UNION
END TYPE

Access to the elements has to be available in the following manners: TEST%test1, TEST%test2, TEST%test3

My thoughts thusfar:

  1. Replace somehow with fortran EQUIVALENCE.
  2. Define the structs in C/C++ and somehow make them visible to the FORTRAN code (doubt that this is possible)

I imagine that there must have been lots of refactoring of f77 to f90/95 when the UNION and MAP were excluded from the standard. How if at all was/is this handled?

EDIT: The accepted answer has a workaround to allow memory overlap, but as far as preserving the API, it is not possible.


Solution

  • UNION and MAP were never part of any FORTRAN standard, they are vendor extensions. (See, e.g., http://fortranwiki.org/fortran/show/Modernizing+Old+Fortran). So they weren't really excluded from the Fortran 90/95 standard. They cause variables to overlap in memory. If the code actually uses this feature, then you will need to use equivalence. The preferred way to move data between variables of different types without conversion is the transfer intrinsic, but to you that you would have to identify every place where a conversion is necessary, while with equivalence it is taking place implicitly. Of course, that makes the code less understandable. If the memory overlays are just to save space and the equivalence of the variables is not used, then you could get rid of this "feature". If the code is like your example, with small integers, then I'd guess that the memory overlay is being used. If the overlays are large arrays, it might have been done to conserve memory. If these declarations were also creating new types, you could use user defined types, which are definitely part of Fortran >=90.

    If the code is using memory equivalence of variables of different types, this might not be portable, e.g., the internal representation of integers and reals are probably different between the machine on which this code originally ran and the current machine. Or perhaps the variables are just being used to store bits. There is a lot to figure out.

    P.S. In response to the question in the comment, here is a code sample. But .... to be clear ... I do not think that using equivalence is good coding pratice. With the compiler options that I normally use with gfortran to debug code, gfortran rejects this code. With looser options, gfortran will compile it. So will ifort.

    module my_types
    
    use ISO_FORTRAN_ENV
    
    type test_p1_type
        sequence
        integer (int32) :: int1
        integer (int32) :: int2
    end type test_p1_type
    
    type test_p2_type
       sequence
       integer (int64) :: int3
    end type test_p2_type
    
    end module my_types
    
    
    program test
    
    use my_types
    
    type (test_p1_type) :: test_p1
    type (test_p2_type) :: test_p2
    
    equivalence (test_p1, test_p2)
    
    test_p1 % int1 = 2
    test_p1 % int1 = 4
    
    write (*, *) test_p1 % int1, test_p1 % int2, test_p2 % int3
    
    end program test