Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29283 Discussions

Issue with the usage of Fortran2003 OO advanced features

Alberto_F__M_
Beginner
2,272 Views

Dear All,

for a new project, we are considering the exploitation of some of the advanced features of the Fortran 2003 standard, essentially run-time polymorphism via abstract data types.

The attached package contains a set of several Fortran 2003 sources files (together with the corresponding compilation bash script) that declare
two abstract data types for an operator [type(abs_operator)] (in its strict linear algebra sense, as e.g., a matrix) and its operands [type(abs_operands)] (e.g., a vector), respectively. An operator "is applied" to an operand, and returns a (pointer to) an operand. This "is applied" action is implemented thorough a deferred function of the operator.  [The current implementation of a matrix and a vector is only a toy implementation, don't
pay too much attention into it].

Besides, we would like to create new operators by combining existing ones using overloaded +, *, etc. In order to overload +, a realization of an operator, type(sum_abs_operator), is declared, and its constructor, that takes two operators, and returns type(sum_abs_operator),
is used for that purpose. The same strategy is used for *. Such overloading is done for the operator abstract data type.

Using all these machinery as currently implemented, we are getting SIGSEV when executing the main program (drive_fops.f90) with ifort 13.0.1., 14.0.1, and 14.0.2 (the ones that we could test so far). In particular, in the implementation of the apply method corresponding to type(sum_abs_operator):

  function sum_abs_operator_apply(op,arg) result(res)
    implicit none
    class(sum_abs_operator), intent(in)  :: op
    class(abs_operand)     , intent(in)  :: arg
    class(abs_operand)     , pointer     :: res
    res => op%op1%apply(arg) + op%op2%apply(arg)
  end function sum_abs_operator_apply

a SIGSEV is triggered during the evaluation of " res=> ...". However, if implemented as:

  function sum_abs_operator_apply(op,arg) result(res)
    implicit none
    class(sum_abs_operator), intent(in)  :: op
    class(abs_operand)     , intent(in)  :: arg
    class(abs_operand)     , pointer     :: res
    class(abs_operand)     , pointer     :: tmp1, tmp2

    tmp1 => op%op1%apply(arg)
    tmp2 => op%op2%apply(arg)
    res => tmp1 + tmp2
  end function sum_abs_operator_apply

then everything works fine (and they seem to be pretty similar to each other). The strange
thing about the SIGSEV is that during the evaluation of " res=> ...", it seems that the
compiler is not calling the vector realization of the deferred function that overloads
+ for the abstract operand, but that of the abstract operator (i.e., sum_abs_operator_construct).

May be there is no issue, and it is our missunderstanding, but we
have no clue about what could be causing this. We would highly appreciate any advice
that you could give us in that respect. Also, as we are beginning the usage of
these OO features of Fortran2003 we would also appreciate if you have any suggestion
on how to implement all this machinery in a better/cleaner/safer way (if any).

Thanks very much in advance.

Best regards,
 Alberto.

0 Kudos
19 Replies
Alberto_F__M_
Beginner
2,272 Views

Dear All,

find attached a bug-fix (related to unappropriate pointer handling) for two of the files included in f03oo_issue_reproducer.tgz. Despite this bug-fix, the issue still persists.

Best regards,

 Alberto.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,272 Views

See what the following do:

res => (op%op1%apply(arg) + op%op2%apply(arg))

res => ((op%op1%apply(arg)) + (op%op2%apply(arg)))

RE: drive_fops

The deallocate's at the end are likely problematic as the pointee may not be allocatable (in the case of v it is not allocatable)

Jim Dempsey

0 Kudos
Alberto_F__M_
Beginner
2,272 Views

Dear Jim,

thanks for your response. The expressions you provided do not compile (see error messages below). I do not actually understand the error message. Any clue of what's going on ?

Best regards,

Alberto.

 

ifort -c -module Objects -g -O0 -r8 -traceback -debug all -check all -ftrapuv -stand f03 -o Objects/foperator.o foperator.f90
foperator.f90(140): error #6678: When the target is an expression it must deliver a pointer result.
    res => ( op%op1%apply(arg) + op%op2%apply(arg) )
-------------------------------^

ifort -c -module Objects -g -O0 -r8 -traceback -debug all -check all -ftrapuv -stand f03 -o Objects/foperator.o foperator.f90
foperator.f90(140): error #6678: When the target is an expression it must deliver a pointer result.
    res => ( (op%op1%apply(arg)) + (op%op2%apply(arg)) )
---------------------------------^

 

 

 

0 Kudos
Steven_L_Intel1
Employee
2,272 Views

You're using pointer assignment (=>). Here you probably want just intrinsic assignment (=). I have not looked at your whole code.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,272 Views

It looked to me as if the pointer=> construct was intended to point to the temporary expression result. I haven't read the latest standards to see if this were permitted. I apologize for any inconvenience my reply may have caused.

The assignment operator (=) will work, but it may also require a copy operation (though the optimization process may result in generating the result in the lhs of = as opposed to in a temp then copy.

An alternate method might be to use the ASSOCIATE which may produce the same functionality as intended by the code using the pointer=>.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
2,272 Views

No, you can't point to an expression. You can only point to things that have the TARGET attribute and there is no way to give an expression that attribute.

0 Kudos
Javier_Principe
Beginner
2,272 Views

Sure? Here "+" is (should be) overloaded with a function that returns a pointer. As far as I understand you can point to a pointer, right? I mean, a pointer is intrinsically a target, right? Would the assignment operator work in this case? I would say no.

In the example posted by Alberto (we work together) everything works fine when doing

tmp1 + tmp2

both being pointers defined locally whereas doing

op%op1%apply(arg) + op%op2%apply(arg)

a SIGSEV occurs.

If we (Alberto and me) are right, in the second case the compiler is overloading + with the wrong function (sum_abs_operator_constructor), the one acting on op which is a type that bounds the procedure apply that returns a vector, instead of doing it with the one acting on vectors (addvec). Introducing local pointers tmp => op%op1%apply(arg) everything works fine.

Many thanks!

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,272 Views

Putting together what Steve last said  you can't point to an expression, which in the case I presented was a result of an expression, and which appears to be what you want for desired behavior. It would then lead to res => tmp1 + tmp2 producing a result of an expression of which you are assigning a pointer to. The fact that the compiler does not emit an error message would then be indicative of an error in the compiler.

In your attached .f90 files you return a pointer to a newly allocated object, which is correct. In the code presented in first post you do not, which is wrong. You could do something like:

 function sum_abs_operator_apply(op,arg) result(res)
     implicit none
     class(sum_abs_operator), intent(in)  :: op
     class(abs_operand)     , intent(in)  :: arg
     class(abs_operand)     , pointer     :: res
     class(abs_operand)     , SAVE      :: res_save
     res_save = op%op1%apply(arg) + op%op2%apply(arg)
     res => res_save
   end function sum_abs_operator_apply

However, this restricts your code to having only one sum_abs_operator_apply object pending at any one time. And code that would not be thread safe.

While you could ALLOCATE the return object and point res at it, then you have to assure that somehow the object is deleted at the appropriate time. This would mean you would need to add reference counting and garbage collection, etc...

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,272 Views

Or consider:

 function sum_abs_operator_apply(op,arg) result(res)
     implicit none
     class(sum_abs_operator), intent(in)  :: op
     class(abs_operand)     , intent(in)  :: arg
     class(abs_operand)     , pointer     :: res
     integer, parameter                   :: MAX_LIFETIME = 100
     class(abs_operand)     , SAVE        :: res_save(MAX_LIFETIME)
     integer                , SAVE        :: i = 1 
     res_save(i) = op%op1%apply(arg) + op%op2%apply(arg)
     res => res_save
     i = i + 1
     if(i .gt. MAX_LIFETIME) i = 1
   end function sum_abs_operator_apply

This would provide a longer lifetime. You will have to decide what is safe for the lifetime.

Jim Dempsey

0 Kudos
Javier_Principe
Beginner
2,272 Views

Jim, your code does not compile (see the errors below). Once again:

+ is overloaded with a function that returns a pointer

In fact, the following error (which I got in another context using the Intel compiler) explicitly says that you can point to an expression:

error #6678: When the target is an expression it must deliver a pointer result. error #6678: When the target is an expression it must deliver a pointer result.

We are quite convinced that the problem is the wrong overloading but we would be 100% sure. We really appreciate your help in clarifying the issue.

Many thanks,

foperator.f90(150): error #8304: In an intrinsic assignment statement, variable shall not be polymorphic.   [RES_SAVE]
    res_save = op%op1%apply(arg) + op%op2%apply(arg)
----^
foperator.f90(151): error #6796: The variable must have the TARGET attribute or be a subobject of an object with the TARGET attribute, or it must have the POINTER attribute.   [RES_SAVE]
    res => res_save
-----------^
foperator.f90(149): error #8223: An entity declared with the CLASS keyword shall be a dummy argument or have the ALLOCATABLE or POINTER attribute.   [RES_SAVE]
    class(abs_operand)     , SAVE      :: res_save

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,272 Views

Considering the error message:

 function sum_abs_operator_apply(op,arg) result(res)
     implicit none
     class(sum_abs_operator), intent(in)  :: op
     class(abs_operand)     , intent(in)  :: arg
     class(abs_operand)     , pointer     :: res
     integer, parameter                   :: MAX_LIFETIME = 100
     class(abs_operand), pointer, SAVE    :: res_save(MAX_LIFETIME)
     integer                , SAVE        :: i = 1

     select type(arg)
        type is(vector)
          select type(res)
            type is(vector)
               if(.not.associated(res_save(i))) allocate(vector::res_save(i))
               res = res_save(i) ! note = to copy pointer not =>, though => may work as well
               i = i + 1
               if(i .gt. MAX_LIFETIME) i = 1
             ! type is(...)
          end select
        class default
          write(*,*) 'This realization of operator (vector) cannot be applied'
          write(*,*) 'to this realization of operand'
     end select
   end function sum_abs_operator_apply

Would that work?

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,272 Views

Note, it would be better to take the array of pointers out of the function and place them in the scope of the module (with the contains function sum_abs_...) and use multiple arrays of your various types. These arrays can then have a proper init to NULLIFY the initial entries, and if desired DEALLOCATE's to reclaim memory at appropriate times.

Jim Dempsey

0 Kudos
Javier_Principe
Beginner
2,272 Views

We have compiled the code using the IBM compiler and the problem disappeared. It is quite clear that this an IFC issue: it is overloading the wrong function.

Best

0 Kudos
Steven_L_Intel1
Employee
2,272 Views

Javier, which code did you compile? Please attach the source you used.

0 Kudos
Javier_Principe
Beginner
2,272 Views

The same code Alberto posted with the minor corrections he uploaded afterwards (the bug he corrected is unrelated to the issue). I attach it again in a single package to make it easier for you. Download it, compile.sh and it works. Go to foperator.f90 uncomment line 141, comment lines 146-148, and you will see the SIGSEV. You will also see a print from the (wrongly) overloaded function.

 

 

 

0 Kudos
Steven_L_Intel1
Employee
2,272 Views

Thanks - we'll take a look.

By the way, I see that the build script uses -ftrapuv. I recommend not using that - it doesn't add any value.

0 Kudos
FortranFan
Honored Contributor III
2,272 Views

Javier Principe wrote:

We have compiled the code using the IBM compiler and the problem disappeared. It is quite clear that this an IFC issue: it is overloading the wrong function.

Best

Javier,

Have you tried Intel compiler version 15?  FWIW, your program doesn't generate any segmentation violation error with Intel Fortran 15.0.0.108 on Windows.  The output is as follows:

 XXX
 XXX
 9.00000000000000 9.00000000000000
 2.00000000000000 2.00000000000000
 2.00000000000000 2.00000000000000
Press any key to continue . . .

 

0 Kudos
Alberto_F__M_
Beginner
2,272 Views

Dear FortranFan,

just to be sure, did you follow the instructions pointed by Javier to reproduce the issue?, i.e.,

Go to foperator.f90 uncomment line 141, comment lines 146-148, and you will see the SIGSEV.

I tried Intel Fortran compiler for Linux, versions 14.0.3.174, 14.0.4.211, and 15.0.0.090, and the SIGSEV is still there.

Best regards,

Alberto.

0 Kudos
Steven_L_Intel1
Employee
2,272 Views

I was able to reproduce the problem in 15.0.

0 Kudos
Reply