Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29030 Discussions

'use only' nonexistent variable is accepted if the name clashes with procedure parameter

HarmenW
Novice
1,216 Views

See https://godbolt.org/z/dssaono3d line 11
Both ifx and ifort accept it, every other compiler that I try rejects this code. Is this a compiler bug?

0 Kudos
1 Solution
Ron_Green
Moderator
1,153 Views

I will open a feature request for a warning for this case.

View solution in original post

15 Replies
JohnNichols
Valued Contributor III
1,164 Views

Please add the code so one does not have to go and find it, I know it is simple but it would be simpler to do this. 

module mod_a
    implicit none
    private
end module mod_a

module mod_b
    implicit none
    private
    contains
    subroutine f(x)
        use mod_a, only: x ! <== This should not be possible!
        integer, intent(out) :: x
        x = 10
    end subroutine f
end module mod_b

program main
    use mod_b, only: 
    implicit none
end program main

original above and then modified 

module mod_a
    implicit none
    private
end module mod_a

module mod_b
    implicit none
    public
    contains
    subroutine f(x)
        use mod_a, only: x ! <== This should not be possible!
        integer, intent(out) :: x
        x = 10
    end subroutine f
end module mod_b

program main
    use mod_b, only: f
    implicit none
    integer X
    x = 1
    call f(x)
    write(*,*)X
end program main

It compiles and runs with minor mods,  mod_a is never called so I assume the compiler is smart enough to ignore it.  but it should flag an error. 

0 Kudos
Ron_Green
Moderator
1,154 Views

I will open a feature request for a warning for this case.

JohnNichols
Valued Contributor III
1,139 Views
module mod_a
    implicit none
    public
    contains
    subroutine x1(f)
    integer, intent(INOUT) :: f
    
    f = 2
    return
    end subroutine x1
end module mod_a

module mod_b
    implicit none
    public
    contains
    subroutine f(x)
        use mod_a, only: x1 ! <== This should not be possible!
        integer, intent(out) :: x
        integer a
        a = 200
        write(*,*)a,x
        call x1(a)
        write(*,*)a
    end subroutine f
end module mod_b

program main
    use mod_b, only: f
    implicit none
    integer X
    x = 1
        write(*,*)x
    call f(x)
    write(*,*)X
end program main

Why does line 22 not throw an error as the value coming in should be indeterminate, even though I set it in main.  It prints as 1.  intent(out) should not pass anything in, that is intent(in) or intent(inout)

0 Kudos
andrew_4619
Honored Contributor III
1,085 Views

Well line 22 is a bug in the code, but the compiler is not obliged to tell you that, like with many code bugs. In standard speak on entry X becomes undefined, that does not mean the value in memory necessarily changes, it may or may not.  It is undefined. Warn Uninit, might give an error but that feature in Intel is pretty hit and miss with scalers. 

0 Kudos
JohnNichols
Valued Contributor III
1,006 Views

Fortran is pass by reference. So I understand what you are saying, but the INTENT(OUT) should override the pass by reference otherwise it is no different to INTENT(INOUT), there has to be an order of precedence.  

X11 should not be the same as X coming in, but X is the same as X11 going out.  

Otherwise intent(in) has no meaning in reality. 

 

0 Kudos
andrew_4619
Honored Contributor III
991 Views

Intent(out) does do more for vars with ptr or allocatable attributes or derived types with components that have an initialiser/default. Other than that you are asking for more than the  standard defines and what it does define is clear (but maybe not obvious). It is one of those things you just have to get right as a programmer.  The compiler in most instances does stop you redefining intent(in) where it can see that you are violating that, e.g. simple assignment.

0 Kudos
JohnNichols
Valued Contributor III
981 Views

I understand what you are saying, but I disagree with the philosophy, if I write intent(out) then the compiler should by default discard any value I read into the call, otherwise there is no point to the intent statement, it definitely blocks the out if I leave it out. 

I have not read the standard, so could you show me where to find it?  

 

0 Kudos
Ron_Green
Moderator
1,112 Views

Feature Request ID is CMPLRLLVM-66333

HarmenW
Novice
1,047 Views
0 Kudos
JohnNichols
Valued Contributor III
1,012 Views
INTENT
Statement and Attribute: Specifies the intended use of one or more dummy arguments.

The INTENT attribute can be specified in a type declaration statement or an INTENT statement, and takes one of the following forms:

Type Declaration Statement:

type,[att-ls,] INTENT (intent-spec) [, att-ls] :: d-arg[, d-arg]...

Statement:

INTENT (intent-spec) [::] d-arg[, d-arg] ...

type

Is a data type specifier.

att-ls

Is an optional list of attribute specifiers.

intent-spec

Is one of the following specifiers:

IN

Specifies that the dummy argument will be used only to provide data to the procedure. The dummy argument must not be redefined (or become undefined) during execution of the procedure.

OUT

Specifies that the dummy argument will be used to pass data from the procedure back to the calling program. The dummy argument is undefined on entry, although it may have subcomponents that are initialized by default. An undefined argument must be defined before it is referenced in the procedure.

Any associated actual argument must be definable.

INOUT

Specifies that the dummy argument can both provide data to the procedure and return data to the calling program.

Any associated actual argument must be definable.

d-arg

Is the name of a dummy argument or dummy pointer. It cannot be a dummy procedure.

Clearly the Intel Intent is that without "in" then the dummy variable in the procedure is undefined.  An undefined argument must be defined before it is referenced in the procedure. 

Screenshot 2025-03-22 091604.png

module mod_a
    implicit none
    public
    contains
    subroutine x1(f)
    integer, intent(INOUT) :: f
    
    f = 2
    return
    end subroutine x1
end module mod_a

module mod_b
    implicit none
    public
    contains
    subroutine f(x11)
        use mod_a, only: x1 ! <== This should not be possible!
        integer, intent(out) :: x11
        integer a
        a = 200
        write(*,*)a,x11
        call x1(a)
        call x1(x11)
        write(*,*)a,x11
    end subroutine f
end module mod_b

program main
    use mod_b, only: f
    implicit none
    integer X
    x = 1
        write(*,*)x
    call f(x)
    write(*,*)X
end program main

 

Screenshot 2025-03-22 092125.png

This is a compiler bug, at line 22, X11 should be undefined, nothing should have been passed in, but it has been set to X no matter what value I give X, and X and X11 are not the same memory slot.  

 

 

0 Kudos
andrew_4619
Honored Contributor III
990 Views

undefined has a defined meaning within the standard, if you want undefined to mean 'initialised with something' that that isn't what you get. There would be an overhead in doing a default initialisation e.g. NaN, it is down to the programmer  to ensure variables are initalised before use and intent(out) get defined, that compiler can help but it is under no obligation to do so and in some cases couldn't anyway,

0 Kudos
Steve_Lionel
Honored Contributor III
931 Views

Two things. First,  if INTENT is unspecified, then that says nothing about the definition status of the effective argument nor whether it is allowed to be defined in the procedure. Second, Fortran is not "pass by reference", even if it seems that way most of the time.

0 Kudos
JohnNichols
Valued Contributor III
846 Views
    module mod_a
    implicit none
    public
    contains
    subroutine x1(f)
    integer, intent(INOUT) :: f

    f = 2
    return
    end subroutine x1
    end module mod_a

    module mod_b
    implicit none
    public
    contains
    subroutine f(x11)
    use mod_a, only: x1 ! <== This should not be possible!
    integer, intent(out) :: x11
    integer x , a, b, c, d
    
    a = 200
    b = 400
    c = 600
    d = 80000
    
    write(*,30)x11,loc(x11)

    write(*,40)a,loc(a)
     x = loc(x11) - loc(a)
    write(*,20)(x)
     x = loc(b) - loc(a)
    write(*,50)(x)
     x = loc(c) - loc(b)
    write(*,60)(x)
     x = loc(d) - loc(c)
    write(*,70)(x)
    call x1(a)
    call x1(x11)
    write(*,40)a,loc(a)
    write(*,30)x,loc(x11)
    
20  Format("      Numerical difference in X to a location ::   ",I20, "                  in module B")
30  Format("      Value of X11 :: ", I20, "    Location of X11 :: ",I16, "        in module B")
40  Format("      Value of a   :: ", I20, "    Location of a   :: ",I16, "        in module B")
50  Format("      Numerical difference in b to a location ::   ",I20, "                  in module B")
60  Format("      Numerical difference in c to b location ::   ",I20, "                  in module B")
70  Format("      Numerical difference in d to c location ::   ",I20, "                  in module B")
    return
    end subroutine f
    end module mod_b

    program main
    use mod_b, only: f
    implicit none
    integer p 
    integer k 
    integer X
    POINTER(p, k)
    INTEGER j(2)

    integer, target :: a
    integer, pointer :: b
    b => a
    write(*,10) loc(a), loc(b)
10  Format("      Location of a :: ", I20, "    Location of b :: ",I20, "     in main programme")
    x = loc(a) - loc(b)
    write(*,20)(x)
20  Format("      Numerical difference in a to b location ::   ",I20, "                  in main programme")
    x = 100
    write(*,30)x,loc(x)

30  Format("      Value of X :: ", I22, "    Location of X :: ",I18, "        in main programme")
    call f(x)
    write(*,40)x,loc(x)
40  Format("      Value of X :: ", I22, "    Location of X :: ",I18, "        in main programme")

 ! This has the same effect as j(1) = 0, j(2) = 5

 write(*,*)j(1),j(2)
 p = LOC(j)
 write(*,*)j(1),j(2),p,k
 k = 0
 write(*,*)j(1),j(2),p,k
 p = p + SIZEOF(k) ! 4 for 4-byte integer
 write(*,*)j(1),j(2),p,k
 k = 5
 
 write(*,*)j(1),j(2),p,k
    end program main

Screenshot 2025-03-23 105543.png

The Fortran manual said that It is almost always pass by reference, I missed the almost on first reading. 

At line 19 I am thinking I am saying to the program discard any value that comes with X11, but it does not, it has been passed the address and the value.  I was not intending to leave INTENT(IN) out I am assuming that INTENT(OUT) means you discard the in, that is how it appears to be referenced in the INTENT pages I read in the Fortran manuals. 

I borrowed Line 78 to the end from the Intel manual, if you run the code, you never see in the watch window, k and P turns up as an integer 8 and not 4. Perhaps someone could explain the finer points. The order on Line 20 is important, if I interchange the X and A then the numerical difference from B to A rises to 8. 

For all purposes X and X11 are identical at all times. 

If I change line 19 to intent(in) then the compiler honours the not OUT, see picture

 

Screenshot 2025-03-23 110753.png

I was expecting a symmetric function on inout, but it is not.  

0 Kudos
andrew_4619
Honored Contributor III
793 Views

When I read a subroutine and I see intent(out) that tells me:
1) The programmer intended that the variables value will always be defined within the subroutine. If that does not happen that is a programming bug.
2) The variable prior to that definition is undefined and therefore its contents are immaterial. The variable must not be used before it is initialised. If it is then that is a programming bug.


John you are expecting more. You are expecting that because a variable has a value before the call then on entry to the subroutine the corresponding dummy arg should be set to something different otherwise you deem it has been passed in. Why would a compiler waste (potentially a lot of time) time doing that given points 1 and 2?

Steve_Lionel
Honored Contributor III
708 Views

To add to Andrew's point, a dummy argument with INTENT(OUT) becomes undefined at entry to the procedure. If the argument is allocatable and is allocated, it gets automatically deallocated.

0 Kudos
Reply