Internal Procedure Scoping

The following code gives unexpedted results. It prints out “1,2” but I am expecting “2,2.” It seems that the internal procedure, ip_print, always
prints out the global scope value of ival=1, not the enclosing scope value of ival=2.

Is this a bug or part of the Fortran Standard?

        
        module ip
          integer :: ival=1      !global
        contains

          integer function ip_print()
            ip_print=ival   !always returns global ival
          end function

          subroutine ip_test()
            integer :: ival=2    !local
            print*,'%ip_test, ',ip_print(),ival
          end subroutine

        end module

        program test
         use ip
         call ip_test()
        end program

Wrong answers? Let’s take a vote…

% gfortran --version
GNU Fortran (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)
Copyright © 2010 Free Software Foundation, Inc.

% ifort --version
ifort (IFORT) 17.0.1 20161005
Copyright © 1985-2016 Intel Corporation. All rights reserved.

% pgfortran -V
pgfortran 17.10-0 64-bit target on x86-64 Linux -tp sandybridge


% ifort -o test_intel test.f90
% gfortran -o test_gfort test.f90
% pgfortran -o test_pgi test.f90

% test_intel
%ip_test, 1 2
% test_pgi
%ip_test, 1 2
% test_gfort
%ip_test, 1 2

I think all the compilers have unexpected results…

The function “ip_print” isn’t an internal procedure, but a module subprogram. Inside the function the accessible entity “ival” is the host module’s “ival”.

So, “ip_print” is correctly returning the value “1”.

To make the function an internal procedure:

 module ip
  integer :: ival=1      !global
contains

  subroutine ip_test()
    integer :: ival=2    !local
    print*,'%ip_test, ',ip_print(),ival

  contains

    integer function ip_print()
     ip_print=ival   ! accesses the host ip_test's ival
    end function
  end subroutine
end module

The Fortran standard says that ival is defined using “host association” which is the enclosing scope. Why doesn’t ival take on the enclosing scope value, ival=2, when called from ip_test()?

% more test2.f90
module ip
integer :: ival=1 !global
contains

subroutine ip_test()
integer :: ival=2 !local
print*,’%ip_test, ',ip_print(),ival

contains

integer function ip_print()
ip_print=ival ! accesses the host ip_test’s ival
end function
end subroutine
end module


program use_ip
use ip
call ip_test()
end program use_ip

==================================================


subroutine ip_test()

contains function ip_print, so it should be affected by changes to ival
in ip_test.

% gfortran -o test2_gfort test2.f90
% pgfortran -o test2_pgi test2.f90
% ifort -o test2_intel test2.f90
% test2_gfort
%ip_test, 2 2
% test2_pgi
%ip_test, 2 2
% test2_intel
%ip_test, 2 2

So i think we are doing the right thing.

dave

Because, in your original version, the host of each of “ip_print” and “ip_test” is the module. In terms of the Fortran standard “host” isn’t related to the call stack, but where the functions are defined.

That is, while “ip_print” is called (referenced) by “ip_test” its host is still the module “ip”. Only if you make “ip_print” an internal procedure (using “contains”, as in my previous example) of “ip_test” does the host become “ip_test”.

Thanks. There are many ways to get the program to print out the answer that I am expecting.

My question is:

This code seems to be contradicting the Fortran Standard.

If not, where in the Fortran Standard does it state that internal procedures or module subprograms will not use “host association” to define variables, but rather use “global scope” to define variables?

Interestingly, there are two members of the Fortran Standards
Committee across the aisle from me , and they see no problems with the code and the Standard

But rather than argue the standard, create an example that gives
different answers on different compilers, and you will get peoples attention.

dave

Looks like I found the statements in the Fortran Standard(2003) that address my issue.

Section 2.2:

A scoping unit that immediately surrounds another scoping unit is called the host scoping unit (often abbreviated to host).

Sections 2.2.3.2 and 2.2.3.3 define what the host scoping unit is for module and internal procedures and they are the enclosing module and program/subprogram, respectively.

So, indeed, the “surrounding scope” is not always the “host scope.”

Thanks!