Problem with generic-type bound procedure of an abstract type

Problem with generic-type bound procedure of an abstract type

Hi,

The following program gives a compile-time error where I think it shouldn't.

I'm defining a abstract derived-type with a generic type-bound procedure which overloads two procedures which have different arguments,.

The first procedure "Sub_0d" has a input argument corresponding to a scalar derived-type of type Abstract_Type.

The second procedure "Sub_1d" has a input argument corresponding to a 1d-array derived-type of type Abstract_Type.

While the call to the first procedure works well, there is an error for the second one.

Note that the error message is different if the procedure is called using the generic name "Sub" or the actual procedure "Sub_1d".

Is there a coding mistake somewhere or is it a compiler bug ?

Thanks.

Module My_Module

	  implicit none

	  private

	  public        ::      Abstract_Type

	  Type  ,abstract               ::      Abstract_Type

	  contains

	    generic                     ::      Sub => Sub_0d, Sub_1d

	    procedure   ,public         ::      Sub_0d

	    procedure   ,public         ::      Sub_1d

	  End Type

	  contains

	Subroutine Sub_0d( This, Var )

	  class(Abstract_Type)                            ,intent(inout)  ::      This

	  class(Abstract_Type)                            ,intent(in)     ::      Var

	End Subroutine

	Subroutine Sub_1d( This, Var )

	  class(Abstract_Type)                            ,intent(inout)  ::      This

	  class(Abstract_Type) ,dimension(:) ,allocatable ,intent(in)     ::      Var

	End Subroutine

	End Module
Program Main

	  use My_Module ,only: Abstract_Type

	  implicit none

	  Type ,extends(Abstract_Type)  ::      Extended_Type

	  End Type

	  type(Extended_Type)                                   ::      V0, W0

	  type(Extended_Type) ,dimension(:)     ,allocatable    ::      V1

	  write(*,"('Allocating V1 => V1(1)')")

	  allocate( V1(1) )

	  write(*,"('Calling W0%Sub(V0)')")

	  call W0%Sub(V0)                               ! ===> ok

	  write(*,"('Calling W0%Sub(V1)')")

	  call W0%Sub(V1)                               ! ===> error #8486: There is no matching specific subroutine for this type bound generic subroutine call.   [SUB]

	  write(*,"('Calling W0%Sub_1d(V1)')")

	  call W0%Sub_1d(V1)                            ! ===> error #6633: The type of the actual argument differs from the type of the dummy argument.   [V1]

	End Program

13 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

It looks like a compiler bug to me; you should follow-up with Intel Premier Support and seek further clarification if that is the case indeed.  If you do, please post your findings here so others can learn from them.

Separately, some questions on your code example though:

Citação:

flying_hermes escreveu:

    Subroutine Sub_1d( This, Var )
      class(Abstract_Type)                            ,intent(inout)  ::      This
      class(Abstract_Type) ,dimension(:) ,allocatable ,intent(in)     ::      Var
    End Subroutine

I'm not sure of the combination of ALLOCATABLE attribute and INTENT(IN): you won't be able to allocate or deallocate Var inside the Sub_1d procedure since it has INTENT(IN).  And your main program allocates the actual argument before calling the Sub_1d procedure, so if that's how you intend it (pun intended! :-)), then do you really need the ALLOCATABLE attribute i.e., are you looking for a copy-in, copy-out of this argument?

Have you retried your compilation with simpler options for Sub_1d and checked if they work?  That is, 1) remove the ALLOCATABLE attribute on Var in Sub_1d, but retain INTENT(IN) and 2) change INTENT(IN) to INTENT(INOUT) on Var in Sub_1d but retain ALLOCATABLE.  The generic resolution should then have no problems.

As you suggest, I will submit this issue one the Intel Premier Support, once I've created myself an account.

As for the use of the "allocatable" and "intent(in)" attributes togeter, it is indeed requested.

As you state, declaring an "intent(in)" dummy variable with the "allocatable" is useless except in one particular case, when one want to perform some operations or not according to whether or not the input variable is allocated. Of course, one could add a conditional instruction in the calling procedure (the main program in my example) which will call the procedure only if the variable is allocated. The problem with this approach is that if the procedure is called using a variable which has not yet been allocated, then a seg fault occur when the variable is used.

Thereore, I believe that the approach using both the "allocatable" and "intent(in)" attributes is more robust since it can handle input agument which are allocated or not. However, in order to be able to call this procedure using variable which are not allocatable, I need to overload a generic procedure with both, the allocatable-variable version and the non-allocatable variable version. I've have not yet test this but, in such a case, it is likely than the the compiler will have  some problem to resolve the generic resolution.

Quoting Steve Lionel from the post http://software.intel.com/en-us/forums/topic/269772:

Citação:

For generic resolution, only the Type, Kind and Rank of arguments are considered. Each specific procedure in a generic must be distinguishable from all others by type, kind and/or rank. Other attributes, such as ALLOCATABLE or POINTER are not considered

Quote:

flying_hermes wrote:

.. declaring an "intent(in)" dummy variable with the "allocatable" is useless except in one particular case, when one want to perform some operations or not according to whether or not the input variable is allocated. ..

As I mentioned above, most compilers are likely to perform a copy-in, copy-out of the argument with the ALLOCATABLE attribute - I'd assume Intel Fortran does as well.  So there could be a performance penalty depending on the size of the argument.

Ok, I didn't catch this point in your first post.

This performance penalty can indeed be an issue is some case...

Knowing that, I might come back to the "traditional" implementation that requires that the calling procedure checks if a variable is allocated before calling the procedure. In other words, responsibility for checking that a given variable is allocated before actually using it is on the calling procedure.

Thanks for your advice anyway.

A couple of additional considerations:

  • You can consider adding another "overloaded" procedure to your GENERIC Sub that takes no argument.  Your main program can then have a conditional invocation of Sub with the appropriate arguments:

    IF (ALLOCATED(V1)) THEN
       CALL W0%Sub(V1)
    ELSE
       CALL W0%Sub()
    END IF

  • With Fortran 2008, you should be able simply mark the dummy argument as OPTIONAL without the need to apply the ALLOCATABLE attribute and thus avoid copy-in, copy-out.  This will allow you to get past this situation: "if the procedure is called using a variable which has not yet been allocated, then a seg fault occur when the variable is used."   This is because in Fortran 2008 an unallocated actual argument can be seen as absent in the called procedure if the dummy is marked as OPTIONAL and this can be detected by the IF (PRESENT(Var)) statement.  I don't think this feature is available yet in Intel Fortran.

flying_hermes, the text of mine you quoted was true when I wrote it in 2009, but not today. Fortran 2008 added POINTER/ALLOCATABLE as a distinguishing characteristic. Intel Fortran doesn't fully support that yet.

However, I don't see that as being germane to this problem, which I agree is a compiler bug. I will report it to the developers and let you know of any progress. Issue ID is DPD200253681.

Steve - Intel Developer Support

Quote:

FortranFan wrote:

Quote:

flying_hermes wrote:

.. declaring an "intent(in)" dummy variable with the "allocatable" is useless except in one particular case, when one want to perform some operations or not according to whether or not the input variable is allocated. ..

 

As I mentioned above, most compilers are likely to perform a copy-in, copy-out of the argument with the ALLOCATABLE attribute - I'd assume Intel Fortran does as well.  So there could be a performance penalty depending on the size of the argument.

Why do you think copy-in/copy-out for the intent(in), allocatable argument?  That doesn't sound right to me.

I agree with Ian - no copy is done here. In fact, it would never be done when the dummy argument is assumed-shape (unless it also has the VALUE attribute, I suppose, and then it's copy-in only.)

But I also agree that the only time you should give a dummy argument the ALLOCATABLE attribute is if you plan to change its allocation status within the routine.

Steve - Intel Developer Support

Citação:

IanH escreveu:

Quote:

FortranFan wrote:

Quote:

flying_hermes wrote:

.. declaring an "intent(in)" dummy variable with the "allocatable" is useless except in one particular case, when one want to perform some operations or not according to whether or not the input variable is allocated. ..

 

As I mentioned above, most compilers are likely to perform a copy-in, copy-out of the argument with the ALLOCATABLE attribute - I'd assume Intel Fortran does as well. So there could be a performance penalty depending on the size of the argument.

 

Why do you think copy-in/copy-out for the intent(in), allocatable argument? That doesn't sound right to me.

Citação:

Steve Lionel (Intel) escreveu:

I agree with Ian - no copy is done here. In fact, it would never be done when the dummy argument is assumed-shape (unless it also has the VALUE attribute, I suppose, and then it's copy-in only.)

I didn't mean it in the context of INTENT(IN), but with ALLOCATABLE dummy arguments in general.  Unfortunately I don't have an exact example with supporting details to illustrate this, but I made some notes while during "playing around" with ALLOCATABLE dummy arguments in Intel Fortran v11 a while ago where I marked "copy-in/copy-out seems to be taking place to enforce rule 5.7.2(i) in MFE, Fortran 95/2003 Explained".  If you've the book, you may want to refer to section 5.7.2 on restrictions on actual arguments as well as section 12.2.

 

The error messages are correct - this program is not valid. I will admit that I needed help to figure out why.

The key distinction I missed is that the dummy argument Var in Sub_1d is allocatable.  This is covered by 12.5.2.5 in F2008 where it says:

18 2 The actual argument shall be polymorphic if and only if the associated dummy argument is polymorphic, and
19 either both the actual and dummy arguments shall be unlimited polymorphic, or the declared type of the actual
20 argument shall be the same as the declared type of the dummy argument.

Since the actual argument is not polymorphic AND the declared types are not the same, then these are not TKR compatible. It certainly would be nice if ifort gave more detailed error messages in such cases and I will suggest that.

Steve - Intel Developer Support

Thanks Steve.  I understand better now.  The following code compiles ok:

          Type ,extends(Abstract_Type)  ::      Extended_Type
          End Type
          class(Abstract_Type), allocatable                     ::      V0, W0
          class(Abstract_Type), dimension(:)     ,allocatable   ::      V1
          integer :: istat
          write(*,"('Allocating V1 => V1(1)')")
          allocate( Extended_Type :: V0, W0, stat=istat)

	          allocate( Extended_Type :: V1(1), stat=istat )
          write(*,"('Calling W0%Sub(V0)')")
          call W0%Sub(V0)                             
          write(*,"('Calling W0%Sub(V1)')")
          call W0%Sub(V1)                             

Quote:

Steve Lionel (Intel) wrote:

... It certainly would be nice if ifort gave more detailed error messages in such cases and I will suggest that.

Steve,

For whatever it's worth, gfortran 4.9 gives the following errors for the code in the original posting:

gfortran.exe -JRelease\GNU\ -Wall  -g  -std=f2008    -c C:\dev\Fortran\Test8\sor\My_Module.f90
-o Release\GNU\sor\My_Module.o
 
C:\dev\Fortran\Test8\sor\My_Module.f90:64.17:
          call W0%Sub(V1)                         
                      1
Error: Found no matching specific binding for the call to the GENERIC 'sub' at (1)
C:\dev\Fortran\Test8\sor\My_Module.f90:68.25:
          call W0%Sub_1d(V1)                      
                         1
Error: Actual argument to 'var' at (1) must be polymorphic
 
Process terminated with status 1 (0 minute(s), 0 second(s))
2 error(s), 0 warning(s) (0 minute(s), 0 second(s))

I'd say the messages are a bit more descriptive and give good hints to a coder who understands Fortran 2003 (and 2008).

Leave a Comment

Please sign in to add a comment. Not a member? Join today