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

possible bug in loc function on class variable?!

may_ka
Beginner
669 Views

Hi,

the program below produces two different results depending on whether a type member variable is declared as "class" or "type":

 

module mod_tmp
  type :: tmp
    real, allocatable :: x(:,:)
  end type tmp
  type :: xx1
    type(tmp), allocatable :: a
    type(tmp), pointer :: b=>null()
  end type xx1
  type :: xx2
    class(tmp), allocatable :: a
    class(tmp), pointer :: b=>null()
  end type xx2
end module mod_tmp
program test
  use mod_tmp, only: xx1, xx2
  implicit none
  class(xx1), allocatable :: a1
  class(xx2), allocatable :: a2
  allocate(a1)
  write(*,*) loc(a1%b),loc(a1%a)
  allocate(a2)
  write(*,*) loc(a2%b),loc(a2%a)
end program test

 

 

compiled with ifort version 19.0.5 or 19.1.2 the result is

 

                     0                     0
              15406432              15406304

 

whereas gfortran, version 10.2 gives

 

                    0                    0
                    0                    0

 

 

I would suggest that this is a bug but before I launch a support ticket I would like somebody literate in the standard to confirm.

op: Linux, kernel version 5.9.10, ifort version 19.0.5 and 19.1.2

Thanks.

BTW: the drop down list for inserting code does not show "FORTRAN"  or "bash" any longer?! Found with firefox 83 and chromium 87.

0 Kudos
1 Solution
FortranFan
Honored Contributor II
654 Views

For anyone interested in the Fortran standard, the closest the standard language comes to a similar facility is the C_LOC module intrinsic function whose interface is defined in ISO_C_BINDING intrinsic module.  As readers may know, C_LOC works in conjunction with a companion C processor.

For a situation similar to that by OP, a coder has to go through rigmarole to work with C_LOC e.g., the dummy argument must have TARGET attribute; if it is ALLOCATABLE, it must be allocated; and if a POINTER, it must be associated (i.e., it cannot be disassociated via => null() assignment), etc.

Here's an example which I contend is standard-conforming.  In my experience with C interoperability features, Intel compiler works as expected:

module mod_tmp
   type :: tmp
      real, allocatable :: x(:,:)
   end type tmp
   type :: xx1
      type(tmp), allocatable :: a
      type(tmp), pointer :: b=>null()
   end type xx1
   type :: xx2
      class(tmp), allocatable :: a
      class(tmp), pointer :: b=>null()
   end type xx2
contains
   subroutine init_xx1( arg )
      class(xx1), allocatable, intent(out) :: arg
      allocate( arg )
      allocate( arg%a, arg%b )
      allocate( arg%a%x(1,1), arg%b%x(1,1) )
   end subroutine
   subroutine init_xx2( arg )
      class(xx2), allocatable, intent(out) :: arg
      allocate( arg )
      allocate( arg%a, arg%b )
      allocate( arg%a%x(1,1), arg%b%x(1,1) )
   end subroutine
end module mod_tmp

program test

   use, intrinsic :: iso_c_binding, only : c_loc, CS => c_size_t
   use mod_tmp, only: xx1, xx2, init_xx1, init_xx2

   implicit none

   class(xx1), allocatable, target :: a1
   class(xx2), allocatable, target :: a2
   integer(kind=CS) :: addr_a, addr_b

   call init_xx1(a1)
   addr_a = transfer( source=c_loc(a1%a), mold=addr_a)
   addr_b = transfer( source=c_loc(a1%a), mold=addr_a)
   print "(g0,1x,z0,1x,z0)", "Address of a1 components: ", addr_a, addr_b

   call init_xx2(a2)
   addr_a = transfer( source=c_loc(a2%a), mold=addr_a)
   addr_b = transfer( source=c_loc(a2%a), mold=addr_a)
   print "(g0,1x,z0,1x,z0)", "Address of a2 components: ", addr_a, addr_b

end program test

 

Upon execution using Intel Fortran 19.1, Update 3, the output is as expected:

Address of a1 components:  16B667A45D0 16B667A45D0
Address of a2 components:  16B667ACEF0 16B667ACEF0
Press any key to continue . . .

View solution in original post

4 Replies
andrew_4619
Honored Contributor II
656 Views

Two things:

1) loc is not standard Fortran it is a vendor extension. So it can behave however the compiler vendor wants it to.

2) doing anything with an unallocated variable is basically wrong IMO that is why we have the allocated(var) function. 

0 Kudos
FortranFan
Honored Contributor II
655 Views
@may_ka wrote:

.. I would like somebody literate in the standard to confirm..

 

@may_ka,

LOC has nothing to do with the Fortran standard, rather it's an Intel facility.

So you can contact Intel support directly and inquire with them on details on how they intend their LOC function to work under your circumstance.

0 Kudos
FortranFan
Honored Contributor II
655 Views

For anyone interested in the Fortran standard, the closest the standard language comes to a similar facility is the C_LOC module intrinsic function whose interface is defined in ISO_C_BINDING intrinsic module.  As readers may know, C_LOC works in conjunction with a companion C processor.

For a situation similar to that by OP, a coder has to go through rigmarole to work with C_LOC e.g., the dummy argument must have TARGET attribute; if it is ALLOCATABLE, it must be allocated; and if a POINTER, it must be associated (i.e., it cannot be disassociated via => null() assignment), etc.

Here's an example which I contend is standard-conforming.  In my experience with C interoperability features, Intel compiler works as expected:

module mod_tmp
   type :: tmp
      real, allocatable :: x(:,:)
   end type tmp
   type :: xx1
      type(tmp), allocatable :: a
      type(tmp), pointer :: b=>null()
   end type xx1
   type :: xx2
      class(tmp), allocatable :: a
      class(tmp), pointer :: b=>null()
   end type xx2
contains
   subroutine init_xx1( arg )
      class(xx1), allocatable, intent(out) :: arg
      allocate( arg )
      allocate( arg%a, arg%b )
      allocate( arg%a%x(1,1), arg%b%x(1,1) )
   end subroutine
   subroutine init_xx2( arg )
      class(xx2), allocatable, intent(out) :: arg
      allocate( arg )
      allocate( arg%a, arg%b )
      allocate( arg%a%x(1,1), arg%b%x(1,1) )
   end subroutine
end module mod_tmp

program test

   use, intrinsic :: iso_c_binding, only : c_loc, CS => c_size_t
   use mod_tmp, only: xx1, xx2, init_xx1, init_xx2

   implicit none

   class(xx1), allocatable, target :: a1
   class(xx2), allocatable, target :: a2
   integer(kind=CS) :: addr_a, addr_b

   call init_xx1(a1)
   addr_a = transfer( source=c_loc(a1%a), mold=addr_a)
   addr_b = transfer( source=c_loc(a1%a), mold=addr_a)
   print "(g0,1x,z0,1x,z0)", "Address of a1 components: ", addr_a, addr_b

   call init_xx2(a2)
   addr_a = transfer( source=c_loc(a2%a), mold=addr_a)
   addr_b = transfer( source=c_loc(a2%a), mold=addr_a)
   print "(g0,1x,z0,1x,z0)", "Address of a2 components: ", addr_a, addr_b

end program test

 

Upon execution using Intel Fortran 19.1, Update 3, the output is as expected:

Address of a1 components:  16B667A45D0 16B667A45D0
Address of a2 components:  16B667ACEF0 16B667ACEF0
Press any key to continue . . .
FortranFan
Honored Contributor II
650 Views

@may_ka ,

To the extent your interest is in Fortran generally including its standard, you may also want to post your queries at this Fortran Discourse site for broader community feedback:

https://fortran-lang.discourse.group/

0 Kudos
Reply