Dynamic type information lost? (PGI 13.7)

The code at the end of this post shows a very specific case where PGI seems to have a bug causing a segfault. The “FooContainer” type has an allocatable component of abstract type (FooBase). If you use an init method to allocate that component based on some input, and then call a type-bound procedure on that component, you get a segfault.

When I was mucking about trying to find a workaround, I found three more things:

  1. It seems to be impossible to use a “select type” construct to get information about the type of my_foo, since you instead get information about “self” (the FooContainer object).

  2. If you copy my_foo, the copy doesn’t seem to have any dynamic type information. If you put it in a select type construct, it will always fall through to the “class default” clause.

  3. If you don’t use the FooContainer_init function to set my_foo, and instead allocate my_foo directly, there didn’t seem to be a problem. Using a type-bound “init” subroutine also seems to do the trick, which ended up being the workaround that I use. This suggests that the real problem here is the assignment from the output of the FooContainer_init function.

(One of my test cases found a different issue, which is that pgfortran doesn’t allow you to allocate “empty” types with no components. I’m not sure why, since this seems explicitly allowed in Fortran; maybe just an unimplemented feature?)



module foo_mod

implicit none

type, abstract :: FooBase
   integer :: a
 contains
   procedure(do_proc), pass(self), deferred :: do_stuff
end type FooBase

abstract interface
   subroutine do_proc(self)
     import
     class(FooBase), intent(in) :: self
   end subroutine do_proc
end interface

type, extends(FooBase) :: Foo
   integer :: b
 contains
   procedure, pass(self) :: do_stuff => really_do_stuff
end type Foo

type :: FooContainer
   class(FooBase), allocatable :: my_foo
 contains
   procedure, pass(self) :: do_stuff_wrap
end type FooContainer

contains

subroutine really_do_stuff(self)
  class(Foo), intent(in) :: self

  print *, "Hi!"

end subroutine really_do_stuff

function FooContainer_init(foo_in) result(res)
  class(FooBase), intent(in) :: foo_in
  type(FooContainer) :: res
  allocate(res%my_foo, source=foo_in)
end function FooContainer_init

subroutine do_stuff_wrap(self)
  class(FooContainer), intent(in) :: self

  call self%my_foo%do_stuff()

end subroutine do_stuff_wrap

end module foo_mod

program test_poly

use foo_mod

implicit none

type(Foo) :: local_foo
type(FooContainer) :: foo_wrap

foo_wrap = FooContainer_init(local_foo)

call foo_wrap%do_stuff_wrap()

end program test_poly

Hi Sean,

Thanks for the report. I filed a problem report (TPR#19589) and sent it to engineering for further investigation.

Best Regards,
Mat

TPR 19589 is fixed now in the 13.10 release.
thanks,
dave

Thanks for the update; the bugs fixed in versions 13.9 and 13.10 have been quite helpful!

Could you also file a TPR for the other issue I encountered? I specifically mean allocating an empty type:

type foo
end type foo

type(foo), allocatable :: x

allocate(x)

end

This causes the following compilation error:

PGF90-S-0151-Empty TYPE, STRUCTURE, UNION, or MAP (test_empty_type.F90: 8)
0 inform, 0 warnings, 1 severes, 0 fatal for MAIN

The main case where you would want to allocate an empty type is to leverage polymorphism, in which case you would declare “class(foo)”; the error actually goes away in that case. But it seems a little inconsistent; I don’t see a reason why the above shouldn’t work.

Hi Sean,

Not sure why but it looks like this one did not get in 13.10. The error does not occur in the pre-release 14.1 compiler, which will be available in January.

  • Mat

This problem is fixed in the 14.1 release.

thanks,
dave

Original case seems OK, but I found one case where an empty type can still cause a segfault in PGI 14.1.

program test_select_type_component

type :: foo
end type foo

type(foo) :: test_foo

! Produces an ICE.
allocate(test_foo, source=foo())

end program test_select_type_component

Hi Sean,

I note that the segfault is still present in 14.3, although it does also print out an error message:

cparrott@galaxy ~/UF $ pgf90 -o test_select test_select.f90
PGF90-S-0198-Illegal use of test_foo in ALLOCATE/DEALLOCATE (test_select.f90: 9)
pgf90-Fatal-/proj/pgi/linux86-64/14.3/bin/pgf901 TERMINATED by signal 11
Arguments to /proj/pgi/linux86-64/14.3/bin/pgf901
/proj/pgi/linux86-64/14.3/bin/pgf901 test_select.f90 -opt 1 -terse 1 -inform warn -nohpf -nostatic -x 19 0x400000 -quad -x 59 4 -x 15 2 -x 49 0x400004 -x 51 0x20 -x 57 0x4c -x 58 0x10000 -x 124 0x1000 -tp sandybridge -x 57 0xfb0000 -x 58 0x78031040 -x 48 4608 -x 49 0x100 -x 120 0x200 -stdinc /proj/pgi/linux86-64/14.3/include-gcc44:/proj/pgi/linux86-64/14.3/include:/usr/local/include:/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include:/usr/include -def unix -def __unix -def __unix__ -def linux -def __linux -def __linux__ -def __NO_MATH_INLINES -def __x86_64 -def __x86_64__ -def __LONG_MAX__=9223372036854775807L -def '__SIZE_TYPE__=unsigned long int' -def '__PTRDIFF_TYPE__=long int' -def __THROW= -def __extension__= -def __amd_64__amd64__ -def __k8 -def __k8__ -def __SSE__ -def __MMX__ -def __SSE2__ -def __SSE3__ -def __SSSE3__ -freeform -vect 48 -y 54 1 -x 70 0x40000000 -modexport /tmp/pgf90C9zhuSjjUpSJ.cmod -modindex /tmp/pgf9089zh0oxWdN09.cmdx -output /tmp/pgf9089zh0957Lndt.ilm

Still, the compiler probably shouldn’t crash in this case. I’ll file a report.

Best regards,

+chris

Oops. I meant to post this valid code (which has the same issue):

program test_select_type_component

type :: foo
end type foo

type(foo), allocatable :: test_foo

! Produces an ICE.
allocate(test_foo, source=foo())

end program test_select_type_component

TPR 20200 - “Improper ALLOCATE statement triggers segfault in compiler”
has been fixed in the current 14.6 release.

thanks,
dave