Inconsistency between arguments, Valid ?

Inconsistency between arguments, Valid ?

Hi,

I'm wondering is the following code is valid.

I'm defining a type bound procedure which has 2 argument:

  1. the passed-object dummy argument with the attribute 'intent(inout)'
  2. a integer variable with the attribute 'intent(in)'

If the actual argument associated to the dummy argument n°2 is a component of the passed-object dummy argument and if this component is modified in the TBP, then there is an inconsistency since the argument n°2 is declared as 'intent(in)' but its value is actually changing.

Below, an example which run without any warnings or errors

! ifort main.f90; ./a.out
Module MyModule
  implicit none
  private
  public        ::      MyType
  Type          ::      MyType
    integer     ::      Var
  contains
    procedure   ,public ::      Do_Something_Inconsistent
  End Type
  contains
Subroutine Do_Something_Inconsistent( This, Var )
  class(MyType)         ,intent(inout)  ::      This
  integer               ,intent(in)     ::      Var
  This%Var      =       Var + 1
End Subroutine
End Module
Program Main
  use MyModule  ,only:  MyType
  implicit none
  type(MyType)  ::      Obj
  Obj%Var       =       1       
  write(*,"('BEFORE: Obj%Var = ',g0)") Obj%Var
  call Obj%Do_Something_Inconsistent( Obj%Var )         ! Is this valid
  write(*,"('AFTER:  Obj%Var = ',g0)") Obj%Var
End Program

sd

12 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Steve Lionel (Intel)'s picture

It's not legal Fortran, as it violates the aliasing rules, but a compiler is not required to diagnose it. Intent has nothing to do with it other than it is the programmer's promise as to what will happen.

Steve

Enclosing the argument in parentheses should make the call valid:

call Obj%Do_Something_Inconsistent( ( Obj%Var ) )

 

jimdempseyatthecove's picture

Steve,

I do not think this "violates" the aliasing rules. Rather, this is an exemplar of "using arguments that alias one another may produce unpredictable results".

Perhaps there could be a compiler option or better, !DEC$, that generates warnings for arguments that alias.

Jim Dempsey

www.quickthreadprogramming.com
Steve Lionel (Intel)'s picture

It's not that simple. The standard doesn't prohibit aliasing, per se, but it restricts what you can do if arguments are aliased, depending on argument attributes. In this case, the program violates the rules of the following section, in particular (3) and (4):

1 12.5.2.13 Restrictions on entities associated with dummy arguments

2 1 While an entity is associated with a dummy argument, the following restrictions hold.

3 (1) Action that affects the allocation status of the entity or a subobject thereof shall be taken through
4 the dummy argument.
5 (2) If the allocation status of the entity or a subobject thereof is affected through the dummy argument,
6 then at any time during the invocation and execution of the procedure, either before or after the
7 allocation or deallocation, it shall be referenced only through the dummy argument.
8 (3) Action that affects the value of the entity or any subobject of it shall be taken only through the
9 dummy argument unless
10 (a) the dummy argument has the POINTER attribute or
11 (b) the dummy argument has the TARGET attribute, the dummy argument does not have INTENT
12 (IN), the dummy argument is a scalar object or an assumed-shape array without the CONTI-
13 GUOUS attribute, and the actual argument is a target other than an array section with a
14 vector subscript.
15 (4) If the value of the entity or any subobject of it is affected through the dummy argument, then at
16 any time during the invocation and execution of the procedure, either before or after the definition,
17 it may be referenced only through that dummy argument unless
18 (a) the dummy argument has the POINTER attribute or
19 (b) the dummy argument has the TARGET attribute, the dummy argument does not have INTENT
20 (IN), the dummy argument is a scalar object or an assumed-shape array without the CONTI-
21 GUOUS attribute, and the actual argument is a target other than an array section with a
22 vector subscript.

This is not something detectable without generating run-time checking code and it's complex. We do have an option, /assume:dummy_alias, which will effectively remove this restriction by disabling certain optimizations.

Steve

What is the effect of enclosing the argument in parentheses ?

mecej4's picture

Trying this program will show you the effect (in essence, the variable becomes an expression):

program xparen
implicit none
integer :: i=3

call sub(i)
write(*,*)i

call sub((i))
write(*,*)i

end program xparen

subroutine sub(i)
implicit none
integer :: i
i=i+1
return
end subroutine sub

 

Steve Lionel (Intel)'s picture

And the effect of that is that a temporary copy of the value is passed - that copy can be modified but the modifications are discarded when the procedure returns.

Steve

Quote:

Steve Lionel (Intel) wrote:

And the effect of that is that a temporary copy of the value is passed - that copy can be modified but the modifications are discarded when the procedure returns.

To avoid any misunderstandings, let me point out that what Steve said is practically true of the Intel implementation and most other implementations, but it is almost backwards with respect to the standard.  The standard expects the expression to be evaluated as part of the procedure invocation and that it should remain unchanged throughout the execution of the procedure.  (Indeed, some implementations put the value of some expressions in read-only memory to give them hardware protection against being changed.)   By copying the value of the expression into a temporary location, the implementation makes it possible to change the value of the original variable without modifying the previously computed value of the expression.

Steve's description is much closer to the standard's idea of the effect of the VALUE attribute on a dummy argument.

-Kurt

 

Quote:

mecej4 wrote:

Trying this program will show you the effect (in essence, the variable becomes an expression):

program xparen
implicit none
integer :: i=3

call sub(i)
write(*,*)i

call sub((i))
write(*,*)i

end program xparen

subroutine sub(i)
implicit none
integer :: i
i=i+1
return
end subroutine sub

 

For the record, this program will work in Intel's implementation and many others, but it does not conform to the Fortran standard, because one is not allowed to redefined a dummy argument associated with an actual argument that is an expression.

jimdempseyatthecove's picture

sd could use VALUE in place of intent(in) to provide some measure of protection in event that the input argument would unexpectedly change through the modification of an intent(inout) variable. This way, sd won't have to hunt down all calls and add () where appropriate.

That said, the code could conceivably have been written to obfuscate the fact that the intention was to expressly modify the intent(in) variable.

Jim Dempsey

www.quickthreadprogramming.com
Steve Lionel (Intel)'s picture

hrichert728 is correct.

Steve

Login to leave a comment.