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

Runtime error on assignment when derived type contains a polymorphic component

John4
Valued Contributor I
459 Views

Hi,

The following program

module mod1

    implicit none
    private
    save

    type :: t0
        integer :: id = 0
    end type

    type, abstract, public :: ta
        character(:), allocatable :: string
        class(t0), allocatable :: zero
    end type

    type, extends(ta), public :: t1
        logical :: status = .FALSE.
    contains
        procedure :: destroy
    end type

contains
    subroutine destroy(this)
        class(t1), intent(INOUT) :: this
        type(t1) :: reset
        integer :: id
    continue
        id = 0
        if (ALLOCATED(this%zero)) id = this%zero%id
        select type(this)
            type is (t1)
                this = reset
        end select
        if (ALLOCATED(this%zero)) this%zero%id = id + 1
    end subroutine

end module mod1

use mod1

implicit none

type(t1) :: a

call a%destroy()

stop 'Finished!'
end

Fails at runtime with

$ ifort -g -traceback test_polyassign.f90 && ./a.out 
forrtl: severe (122): invalid attempt to assign into a pointer that is not associated
Image              PC                Routine            Line        Source             
a.out              00000000004027E9  mod1_mp_destroy_           32  test_polyassign.f90
a.out              00000000004029C5  MAIN__                     45  test_polyassign.f90
a.out              0000000000402366  Unknown               Unknown  Unknown
libc.so.6          00007F8A33034B45  Unknown               Unknown  Unknown
a.out              0000000000402249  Unknown               Unknown  Unknown

Changing line 13 to

        type(t0), allocatable :: zero

Makes the error go away.  Since in both cases the zero component remains unallocated, it seems to me like a compiler bug. Or am I missing something in regards to polymorphism?




 

0 Kudos
5 Replies
Izaak_Beekman
New Contributor II
459 Views

With the current beta version of the compiler I get no runtime errors if I make the following changes:

line 13: class(t0), allocatable :: zero ==> class(t0), pointer :: zero => null()
line 29 and 34: 
if (ALLOCATED(this%zero)) … ==> if (ASSOCIATED(this%zero)) …

I think that the compiler may have been correct in producing an error, because the pointer association status was undefined on line 32. This happens when pointers are created without being explicitly nullified. Adding the default initialization of the zero component of  type ‘ta’ will help ensure that the pointer component zero has a defined pointer association status while it is extant. Furthermore, the allocated intrinsic you were originally using is an inquiry function and, to my knowledge, can’t safely be called with a pointer argument, without first ensuring that the pointer argument is associated. Likely, the undefined pointer association status let it get by the allocated intrinsic without detecting that it was an undefined pointer.

Interestingly, on my system it seems that my pointer components might be implicitly created as disassociated, and getting rid of the => null() default initialization on line 13 does not cause problems; however, this behavior is not guaranteed by the standard and pointer association status must be explicitly set.

 

0 Kudos
John4
Valued Contributor I
459 Views

Hi Izaak,

Sorry if I don't understand your comment very well.  I am not using pointers in the code I posted, so there shouldn't be expectation of default pointer initialization (that's more of an implementation detail for ifort).  And as I mentioned before, the code works by using the specific TYPE in line 13, instead of CLASS ---i.e., in both cases the zero would remain unallocated during assignment in line 32,  so the runtime is issuing an error simply because of the CLASS keyword.

Using the POINTER attribute serves as a workaround, but in the actual code I decided to create the internal procedure

contains
subroutine reset_this(this)
    class(t1), intent(OUT) :: this
end subroutine

And call it in place of the SELECT TYPE construct.  In that case, the INTENT takes care of resetting the argument.


 

0 Kudos
Izaak_Beekman
New Contributor II
459 Views

Ah, I see, my mistake. Yes, this looks like a compiler defect to me and I can confirm that it is still present in the most recent 2015 Beta release.

Good find, and very, very clever work around; I’ll have to keep it in mind if I face similar issues. Hopefuly one of the Intel folks will confirm this as a bug and file a report.

0 Kudos
Steven_L_Intel1
Employee
459 Views

It turns out that we're already working on this one. Issue ID is DPD200252763.

0 Kudos
Steven_L_Intel1
Employee
459 Views

This should be fixed in 16.0.

0 Kudos
Reply