This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug fortran/59560] New: Resolution generic procedure of derived types fail


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59560

            Bug ID: 59560
           Summary: Resolution generic procedure of derived types fail
           Product: gcc
           Version: 4.8.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: klaas_giesbertz at hotmail dot com

I want to achieve some more complicated structure in fortran2008 and I am not
sure how to do it according to the standard. So I am even not sure if it is a
bug, or simply not possible with fortran2008.

I want to make a base class, preferably an abstract one, which promises a
subroutine which operates on TWO arguments of this base class. The derived
class should implement this and there is some other class using this procedure
which only knows about the base class. This was actually possible with gcc 4.7
by declaring both arguments of the subroutine as class. As an example, consider
the following program (sorry, quite lengthy due to the several classes):

module BaseModule
  implicit none
  private

  type, public, abstract :: BaseClass
  contains
    procedure(FuncAbstr), deferred :: Func
  end type

  abstract interface
    subroutine FuncAbstr(self, other)
      import
      class(BaseClass), intent(inout) :: self
      class(BaseClass), intent(in)    :: other
    end subroutine
  end interface
end module

module UseBaseModule
  use BaseModule
  implicit none
  private

  type, public :: UseBaseClass
    class(BaseClass), pointer :: base => null()
  contains
    procedure :: Init
    procedure :: CallFunc
  end type

contains

  subroutine Init(self, base)
    class(UseBaseClass),       intent(inout) :: self
    class(BaseClass), pointer, intent(in)    :: base

    self%base => base
  end subroutine

  subroutine CallFunc(self)
    class(UseBaseClass), intent(inout) :: self
    class(BaseClass), allocatable :: newBase

    allocate(newBase, mold=self%base)

    call newBase%Func(self%base)
  end subroutine
end module

module DerivedModule
  use BaseModule
  implicit none
  private

  type, public, extends(BaseClass) :: DerivedClass
    real :: x
  contains
    procedure :: Func
  end type

contains

  subroutine Func(self, other)
    class(DerivedClass), intent(inout) :: self
    class(DerivedClass), intent(in)    :: other

    self%x = other%x
    write(*,*) 'Derived Func called'
  end subroutine

end module

program Test
  use BaseModule
  use UseBaseModule
  use DerivedModule
  implicit none

  class(BaseClass), allocatable :: derived
  type(UseBaseClass) :: useBase

  allocate(DerivedClass :: derived)

  call useBase%Init(derived)
  call useBase%CallFunc()
end program


This code compiles and runs correctly with gcc4.7.3, but gcc4.8.2 gives the
following compile error:

Test1.f08:58.13:

procedure :: Func
             1
Error: Argument mismatch for the overriding procedure 'func' at (1): Type/rank
mismatch in argument 'other'

and some more which are not relevant.

I actually do not even know if this code is supposed to compile, since it is
not clear to me if such kind of overloading is allowed by the fortran standard.

One way around this problem might be to give up the possibility to use an
abstract type and to use a generic interface with an explicit type for the 2nd
argument of the subroutine. The type is now required to facilite the resolution
of the generic subroutine. However, this generic subroutine is not correctly
resolved. As an example consider the following code (again quite lengthy,
sorry):

module BaseModule
  implicit none
  private

  type, public :: BaseClass
  contains
    procedure :: BaseFunc
    generic   :: Func => BaseFunc
  end type

contains

  subroutine BaseFunc(self, other)
    class(BaseClass), intent(inout) :: self
    type(BaseClass),  intent(in)    :: other

    write(*,*) 'Base Func called'
  end subroutine

end module

module DerivedModule
  use BaseModule
  implicit none
  private

  type, public, extends(BaseClass) :: DerivedClass
    real :: x
  contains
    procedure :: DerivedFunc
    generic   :: Func => DerivedFunc !Extend generic Func
  end type

contains

  subroutine DerivedFunc(self, other)
    class(DerivedClass), intent(inout) :: self
    type(DerivedClass),  intent(in)    :: other

    self%x = other%x
    write(*,*) 'Derived Func called'
  end subroutine

end module

module UseBaseModule
  use BaseModule
  implicit none
  private

  type, public :: UseBaseClass
    class(BaseClass), pointer :: base => null()
  contains
    procedure :: Init
    procedure :: CallFunc
  end type

contains

  subroutine Init(self, base)
    class(UseBaseClass),      intent(inout) :: self
    class(BaseClass), target, intent(in)    :: base

    self%base => base
  end subroutine

  subroutine CallFunc(self)
    class(UseBaseClass), intent(in) :: self
    class(BaseClass), allocatable :: newBase

    allocate(newBase, mold=self%base)

    call newBase%Func(self%base)
  end subroutine
end module

program Test
  use DerivedModule
  use UseBaseModule
  implicit none

  type(DerivedClass) :: derived
  type(UseBaseClass) :: useBase

  call useBase%Init(derived)
  call useBase%CallFunc()
end program

This code compiles both with gcc4.7.3 and gcc4.8.2 and gives in both cases the
incorrect output:
Base Func called
It should have called the DerivedFunc instead. Building a double block of
select types around it solves the problem, but the UseBase needs to know about
the Derived as well to do this, which is not desirable.

Hope someone can help me out.
Klaas Giesbertz


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]