Intel® Fortran Compiler 18.0 Developer Guide and Reference

Variable-Definition Context

A variable can appear in different contexts that imply definition or undefinition of the variable. A reference to a function that returns a data pointer is permitted in such variable-definition contexts.

When a function returns a data pointer, that pointer is always associated with a variable that has the TARGET attribute, either by pointer assignment or by allocation. If a reference to a function that returns a data pointer appears in a variable-definition context, the definable target (with which the function result is associated) is the variable that becomes defined or undefined.

This section describes the different variable-definition contexts in which a function reference returning a data pointer can be used. It also describes the contexts in which data pointer function references are not allowed.

Assignment Statement

Function references returning a data pointer can be used on the left-hand side of an assignment statement. References to type bound and generic procedures are also permitted on the left-hand side of an intrinsic assignment. If the variable on the left-hand side is polymorphic, it must be an allocatable. Therefore, a function returning a polymorphic pointer cannot be used on the left-hand side.

In the following example, function STORAGE returns a data pointer to either the module variable OUTSIDE or to an element of VAR into which a value is stored:

MODULE TMOD
 PUBLIC

 INTEGER, PARAMETER :: N = 10
 INTEGER, TARGET    :: VAR(N)
 INTEGER, TARGET    :: OUTSIDE
 CONTAINS
 FUNCTION STORAGE(KEY) RESULT(LOC)
   INTEGER, INTENT(IN) :: KEY
   INTEGER, POINTER    :: LOC

   IF( KEY .LT. 1 .OR. KEY .GE. N ) THEN
     LOC=> OUTSIDE
   ELSE
     LOC => VAR(KEY)
   ENDIF
 END FUNCTION
END MODULE

PROGRAM MAIN
  USE TMOD
  OUTSIDE = -1
  STORAGE(1) = 11
  STORAGE(0) = 0
  PRINT *, VAR(1), OUTSIDE    ! prints 11, 0
END

The following example shows generic resolution on the left-hand side of an assignment statement:

MODULE MYMODULE
    TYPE :: VEC
        INTEGER :: X(3)
    CONTAINS        
        GENERIC   :: GET => GETELEMENT, GETARRAY
        PROCEDURE :: GETELEMENT
        PROCEDURE :: GETARRAY 
    END TYPE VEC
    CONTAINS
        FUNCTION GETELEMENT( THIS, EL ) RESULT( P )
            IMPLICIT NONE
            CLASS(VEC), TARGET :: THIS
            INTEGER, INTENT(IN) :: EL
            INTEGER, POINTER :: P
            P => THIS%X(EL)
        END FUNCTION GETELEMENT
        
        FUNCTION GETARRAY( THIS ) RESULT( P )
            IMPLICIT NONE
            CLASS(VEC), TARGET :: THIS            
            INTEGER, POINTER :: P(:) ! array pointer
            P => THIS%X
        END FUNCTION GETARRAY
END MODULE MYMODULE

PROGRAM TEST
   USE MYMODULE
   IMPLICIT NONE
   TYPE(VEC) :: MYVEC
   INTEGER   :: Y(3)
   MYVEC%X = [1,2,3]
   Y = [6,7,8]

   ! expected output 1 2 1 2 3
   WRITE(6,*) MYVEC%GET(1), MYVEC%GET(2), MYVEC%GET()

   ! change any array element 
   MYVEC%GET(1) = 4
   MYVEC%GET(2) = 5
   MYVEC%GET(3) = 6

   ! check modified values
   ! expected output 4 5 4 5 6
   WRITE(6,*) MYVEC%GET(1), MYVEC%GET(2), MYVEC%GET()

   MYVEC%GET() = Y          ! array pointer returned

   ! check modified values
   WRITE(6,*)  MYVEC%GET()  ! expected output 6 7 8
END PROGRAM TEST

Argument Association

A function reference returning a data pointer can be used as an actual argument in a reference to a procedure with an explicit interface. If the corresponding dummy argument has the INTENT (OUT) or INTENT (INOUT) attribute, then the pointer function is used in a variable definition context.

The following example uses the function STORAGE, which was defined in the above section "Assignment Statement":

FUNCTION STORAGE(KEY) RESULT(LOC)
   INTEGER, INTENT(IN) :: KEY
   INTEGER, POINTER    :: LOC
..
END FUNCTION
..
STORAGE(2) = 10  
CALL CHANGE_VAL(STORAGE(2)) ! pass storage(2) as actual argument 
PRINT *, VAR(2)             ! prints 50
..
SUBROUTINE CHANGE_VAL(X)
  INTEGER, INTENT(OUT) :: X
  X = X*5    
END SUBROUTINE CHANGE_VAL

The following example shows that the target of the function pointer can get modified inside the subroutine without using the dummy argument corresponding to the function reference:

  MODULE M200C2
    INTEGER, TARGET :: X = 42
  CONTAINS
    FUNCTION FX()
      INTEGER, POINTER :: FX
      FX => X
    END FUNCTION
  END MODULE

  PROGRAM Q1
    USE M200C2
    CALL TEST(X, FX())
    ! note that corresponding dummy is not INTENT (OUT) or INTENT(INOUT).  
    ! FX() is not used in a variable definition context but it still
    !   denotes a variable.
    CONTAINS
    SUBROUTINE TEST(A, B)
    INTEGER, TARGET :: B             
      A = A*10
      PRINT *, A, B                !  prints 420 420
    END SUBROUTINE
  END PROGRAM

SELECT TYPE and ASSOCIATE Construct

A pointer function reference can appear as a variable that is the selector in a SELECT TYPE or ASSOCIATE construct and the associate name of that construct can appear in a variable-definition context. For example:

PROGRAM MAIN 
    INTEGER, TARGET :: DATA = 123 

    ASSOCIATE (ALIAS => FX1()) 
        ALIAS = 456 
        PRINT *, ALIAS, DATA     ! prints 456 456
    END ASSOCIATE 

    SELECT TYPE (ALIAS =>FX2())
        TYPE IS (INTEGER)
          ALIAS = 789
          PRINT *, ALIAS, DATA   ! prints 789 789
    END SELECT

    CONTAINS 
    FUNCTION FX1() 
        INTEGER, POINTER :: FX1
        FX1 => DATA 
    END FUNCTION FX1 
    FUNCTION FX2()
        CLASS(*),POINTER :: FX2
        FX2 => DATA
    END FUNCTION FX2
END PROGRAM MAIN

In the following example, FX() in the ASSOCIATE is a variable and every reference to ALIAS is a reference to the associated variable, so the assignment also changes the value of ALIAS:

PROGRAM MAIN 
    INTEGER, TARGET :: DATA = 123 

    ASSOCIATE (ALIAS => FX1()) 
        DATA = 0 
        PRINT *, ALIAS, DATA     ! prints 0 0
    END ASSOCIATE 

    SELECT TYPE (ALIAS => FX2())
        TYPE IS (INTEGER)
          DATA = 1
          PRINT *, ALIAS, DATA   ! prints 1 1
    END SELECT

    CONTAINS 
    
    FUNCTION FX1 () 
        INTEGER, POINTER :: FX1 
        FX1 => DATA 
    END FUNCTION FX1 

    FUNCTION FX2()
        CLASS(*),POINTER :: FX2
        FX2 => DATA
    END FUNCTION FX2

END PROGRAM MAIN

Input/Output Statements

A pointer function reference can be used as an input item in a READ statement.

A function reference returning a character pointer can be used as an internal file variable in a WRITE statement.

A scalar integer pointer function reference can be an IOSTAT= or a SIZE= specifier in an input/output statement. A scalar character pointer function reference can be an IOMSG= specifier in an input/output statement.

A function returning a scalar pointer, whose datatype matches the specifier, can be specified in an INQUIRE statement except for the three specifiers FILE=, ID=, and UNIT=.

A function returning a scalar integer pointer can be a NEWUNIT= specifier in an OPEN statement.

Consider the following example:

...
    CHARACTER(50), TARGET :: V(33)
    INTEGER, TARGET :: I
    ..
    FUNCTION RET_CHAR(INDEX) RESULT (DCV)
      CHARACTER(50), POINTER :: DCV
      INTEGER :: INDEX
      DCV => V(INDEX)
    END FUNCTION
    FUNCTION RET_INT() RESULT (P)
      INTEGER, POINTER :: P
      P => I
    END FUNCTION
  ...
! an input item in a read stmt
    READ (6, *) RET_INT()
    READ  10, RET_INT()

! an internal file variable in a write stmt  
    WRITE  (RET_CHAR(10), FMT=*) 666

! an IOSTAT=, SIZE=, or IOMSG= specifier in an I/O statement
    READ (10, FMT=*, IOSTAT=RET_INT(), SIZE=RET_INT(), &   
          IOMSG=RET_CHAR(6) ) STR

! a specifier in an inquire statement except FILE=, ID=, and UNIT=
    OPEN(NEWUNIT = NUM, FILE = 'A.TXT', ACTION = 'READ')    
    INQUIRE(NUM,               &
    ACCESS = RET_CHAR(2),      &
    EXIST = RET_CHAR(10),      &
    ID = 13,                   &
    IOSTAT = RET_CHAR(14),     & 
    SIZE = RET_CHAR(30))      
    CLOSE(NUM, STATUS = 'DELETE')

! a NEWUNIT= SPECIFIER in an OPEN statement
    OPEN(NEWUNIT = RET_INT(1), STATUS = 'SCRATCH')
    CLOSE(RET_INT(1), STATUS = 'DELETE') ! allowed on CLOSE

STAT=, ERRMSG=, and ACQUIRED_LOCK= Specifiers

A scalar integer pointer function reference can be used as a STAT= variable. A scalar character pointer function reference can be used as an ERRMSG= variable. STAT= and ERRMSG= are allowed in SYNC ALL, SYNC IMAGES, SYNC MEMORY, LOCK, UNLOCK, ALLOCATE, and DEALLOCATE statements. A scalar logical pointer function reference can be an ACQUIRED_LOCK= specifier in a LOCK statement.

The following example uses RET_CHAR and RET_INT, which were defined in the above section "Input/Output Statements":

    TYPE(LOCK_TYPE) :: LT[*]    
    INTEGER, POINTER     :: AR(:)
    ALLOCATE(AR(2), STAT=RET_INT())   
    DEALLOCATE(AR, STAT=RET_INT())   
 
    LOCK(LT, ACQUIRED_LOCK=GET_LOGICAL(), STAT=RET_INT(), &
    ERRMSG=RET_CHAR()) 
    UNLOCK(LT, STAT=RET_INT(), ERRMSG=RET_CHAR())    
    SYNC IMAGES(*,STAT=RET_INT(), ERRMSG=RET_CHAR())    
    SYNC ALL(STAT=RET_INT(), ERRMSG=RET_CHAR())    
    SYNC MEMORY(STAT=RET_INT(), ERRMSG=RET_CHAR())    

Disallowed Contexts

The Fortran Standard defines both a "variable" and a "variable name". For function F, F is a variable name; F(7) is a function. If F returns a data pointer, F(7) is a variable and can be used in a variable-definition context.

For the following variable-definition contexts, the Fortran Standard specifies that a "variable name" must be used and not a "variable":

A function reference can return a pointer to any data object, even one that cannot be stored into, for example, a USE associated PROTECTed object or a constant. This will not be caught at compile time. It is possible that the target of the pointer function is a local variable from a different subprogram or a private USE associated variable, in which case the pointer returned has an undefined association status.

A More Complex Example

The following example has pointer functions that return data pointers to parameterized derived type objects. The pointer function results are automatic objects whose length type parameters depend on the dummy arguments:

MODULE TMOD
  PUBLIC
  TYPE PDT(K, L)
    INTEGER, KIND :: K
    INTEGER, LEN :: L
    INTEGER :: FIELD(L)
  END TYPE PDT    
END MODULE
PROGRAM MAIN 
    USE TMOD
    IMPLICIT NONE     
    TYPE(PDT(4,2)), TARGET :: PDTOBJ1, OBJ
    TYPE(PDT(2,2)), POINTER :: ACTARG
    CHARACTER(10), TARGET :: C1
    
    BAR() = PDT(4,2)((/5,3/))
    PRINT *, PDTOBJ1%FIELD            ! prints 5 3
        
    AUTO_RES(ACTARG) = PDT(4,2)((/6,4/))
    PRINT *, PDTOBJ1%FIELD            ! prints 6 4
    
    AUTO_CHAR(10) = "TEST"
    PRINT *, C1                       ! prints TEST
    CONTAINS                   
    FUNCTION BAR() RESULT(LOC)
        TYPE(PDT(4,2)), POINTER :: LOC
        LOC => PDTOBJ1
    END FUNCTION
    FUNCTION AUTO_CHAR(DUM1) RESULT(LOC)
         INTEGER, INTENT(IN) :: DUM1
         CHARACTER(DUM1), POINTER :: LOC
         LOC => C1
    END FUNCTION
        
    FUNCTION AUTO_RES(DUM1) RESULT(LOC)
         TYPE(PDT(4,:)), POINTER, INTENT(IN) :: DUM1
         TYPE(PDT(4,DUM1%L)), POINTER :: LOC
         LOC => PDTOBJ1
    END FUNCTION
END PROGRAM