Hello,

here is a fix for PR42769, where a type bound call was resolved statically into a normal procedure call, but using the local procedure (with the same name) instead of the original (and correct) one. It turned out to not be OOP specific, and be a pure module loading problem in the way we associate a symbol number in the module file with the corresponding symbol pointer once module is loaded.

The first module.c hunk fixes comment #14 in the PR. Here, p == NULL, which means that the user didn't ask to load the symbol (USE,ONLY:...), so we can just continue to the next one. However, as an optimization, we try to find the symbol in the current name space and associate the pointer info (mapping module's integer <-> symbol pointer) with it if found to avoid reloading it from the module file if needed. The problem was there was no check that the symbol is really the same, not another symbol with the same name. Fixed by checking symbol's name and module name too. The original code was only reusing the symtree; I took the opportunity to reuse the symbol as well, and the test suite didn't complain :-).

The second module.c hunk fixes comment #24 in the PR. Here, p != NULL: the symbol will have to be loaded. Before creating a new symbol and a new symtree and inserting them in the current name space, we check whether a symtree of the same name exists in the current name space. If it exists and is not ambiguous, it is either the same one as the one from the module, or both are generic so we can reuse the existing symbol in both cases. However, if the symtree in the name space is ambiguous we shall not reuse it as it is different than the one to be loaded. Thus fixed by not reusing it in that case, and letting a unique non ambiguous name being automatically generated later.

The resolve.c hunk fixes comment #34 in the PR. This one is not a module problem, but let's fix all cases in one go. Resolve_call reloads the call's procedure symbol to take into account contained procedure which were not known at parse time. However, it uses the symbol's name (original name) for lookup instead of the symtree's (local name). The resolve.c hunk changes that.

The tests are adapted from comment 14, 24, 34 from pr42769, and the original test cases from pr45836 and pr45900.
Regression tested on x86_64-unknown-linux-gnu. OK for trunk?
4.7?
4.6?

Mikael





2013-01-05  Mikael Morin  <mik...@gcc.gnu.org>

        PR fortran/42769
        PR fortran/45836
        PR fortran/45900
        * module.c (read_module): Don't reuse local symtree if the associated
        symbol isn't exactly the one wanted.  Don't reuse local symtree if it is
        ambiguous.
        * resolve.c (resolve_call): Use symtree's name instead of symbol's to
        lookup the symtree.


diff --git a/module.c b/module.c
index cde5739..e63e510 100644
--- a/module.c
+++ b/module.c
@@ -4656,8 +4656,14 @@ read_module (void)
          if (p == NULL)
            {
              st = gfc_find_symtree (gfc_current_ns->sym_root, name);
-             if (st != NULL)
-               info->u.rsym.symtree = st;
+             if (st != NULL
+                 && strcmp (st->n.sym->name, info->u.rsym.true_name) == 0
+                 && st->n.sym->module != NULL
+                 && strcmp (st->n.sym->module, info->u.rsym.module) == 0)
+               {
+                 info->u.rsym.symtree = st;
+                 info->u.rsym.sym = st->n.sym;
+               }
              continue;
            }
 
@@ -4678,7 +4684,8 @@ read_module (void)
              /* Check for ambiguous symbols.  */
              if (check_for_ambiguous (st->n.sym, info))
                st->ambiguous = 1;
-             info->u.rsym.symtree = st;
+             else
+               info->u.rsym.symtree = st;
            }
          else
            {
diff --git a/resolve.c b/resolve.c
index d4d5eb9..17ee716 100644
--- a/resolve.c
+++ b/resolve.c
@@ -3778,7 +3778,7 @@ resolve_call (gfc_code *c)
   if (csym && gfc_current_ns->parent && csym->ns != gfc_current_ns)
     {
       gfc_symtree *st;
-      gfc_find_sym_tree (csym->name, gfc_current_ns, 1, &st);
+      gfc_find_sym_tree (c->symtree->name, gfc_current_ns, 1, &st);
       sym = st ? st->n.sym : NULL;
       if (sym && csym != sym
              && sym->ns == gfc_current_ns


2013-01-05  Mikael Morin  <mik...@gcc.gnu.org>

        PR fortran/42769
        PR fortran/45836
        PR fortran/45900
        * gfortran.dg/use_23.f90: New test.
        * gfortran.dg/use_24.f90: New test.
        * gfortran.dg/use_25.f90: New test.
        * gfortran.dg/use_26.f90: New test.
        * gfortran.dg/use_27.f90: New test.



! { dg-do compile }
!
! PR fortran/42769
! This test used to ICE in resolve_typebound_procedure because T1's GET
! procedure was wrongly associated to MOD2's MY_GET (instead of the original
! MOD1's MY_GET) in MOD3's SUB.
!
! Original testcase by Salvator Filippone <sfilipp...@uniroma2.it>
! Reduced by Janus Weil <ja...@gcc.gnu.org>

module mod1
  type :: t1
  contains
    procedure, nopass :: get => my_get
  end type
contains 
  logical function my_get()
  end function
end module

module mod2
contains 
  logical function my_get()
  end function
end module

module mod3
contains
  subroutine sub(a)
    use mod2, only: my_get
    use mod1, only: t1
    type(t1) :: a
  end subroutine
end module


use mod2, only: my_get
use mod3, only: sub
end 



! { dg-do run }
!
! PR fortran/42769
! The static resolution of A%GET used to be incorrectly simplified to MOD2's
! MY_GET instead of the original MOD1's MY_GET, depending on the order in which
! MOD1 and MOD2 were use-associated.
!
! Original testcase by Salvator Filippone <sfilipp...@uniroma2.it>
! Reduced by Janus Weil <ja...@gcc.gnu.org>

module mod1
  type :: t1
  contains
    procedure, nopass :: get => my_get
  end type
contains 
  subroutine my_get(i)
    i = 2
  end subroutine
end module

module mod2
contains 
  subroutine my_get(i)    ! must have the same name as the function in mod1
    i = 5
  end subroutine
end module


 call test1()
 call test2()

contains

 subroutine test1()
  use mod2
  use mod1
  type(t1) :: a
  call a%get(j)
  if (j /= 2) call abort
 end subroutine test1

 subroutine test2()
  use mod1
  use mod2
  type(t1) :: a
  call a%get(j)
  if (j /= 2) call abort
 end subroutine test2
end



! { dg-do compile }
!
! PR fortran/42769
! This test used to be rejected because the typebound call A%GET was
! simplified to MY_GET which is an ambiguous name in the main program
! namespace.
!
! Original testcase by Salvator Filippone <sfilipp...@uniroma2.it>
! Reduced by Janus Weil <ja...@gcc.gnu.org>

module mod1
  type :: t1
  contains
    procedure, nopass :: get => my_get
  end type
contains 
  subroutine my_get()
    print *,"my_get (mod1)"
  end subroutine
end module

module mod2
contains 
  subroutine my_get()    ! must have the same name as the function in mod1
    print *,"my_get (mod2)"
  end subroutine
end module

  use mod2
  use mod1
  type(t1) :: a
  call call_get
  contains
  subroutine call_get
    call a%get()
  end subroutine call_get
end


! { dg-do compile }
!
! PR fortran/45836
! The B_TYPE_INSTANCE%SIZERETURN() typebound function used to be rejected on a
! type mismatch because the function was resolved to A's SIZERETURN instead of
! B's because of the ambiguity of the SIZERETURN name in the MAIN namespace.
!
! Original testcase by someone <ort...@gmail.com>

module A
implicit none
    type :: a_type
    private
        integer :: size = 1
    contains
        procedure :: sizeReturn
    end type a_type
    contains
        function sizeReturn( a_type_ )
            implicit none
            integer :: sizeReturn
            class(a_type) :: a_type_

            sizeReturn = a_type_%size
        end function sizeReturn
end module A

module B
implicit none
    type :: b_type
    private
        integer :: size = 2
    contains
        procedure :: sizeReturn
    end type b_type
    contains
        function sizeReturn( b_type_ )
            implicit none
            integer :: sizeReturn
            class(b_type) :: b_type_

            sizeReturn = b_type_%size
        end function sizeReturn
end module B

program main

  call test1
  call test2

contains

  subroutine test1
    use A
    use B
    implicit none
    type(a_type) :: a_type_instance
    type(b_type) :: b_type_instance

    print *, a_type_instance%sizeReturn()
    print *, b_type_instance%sizeReturn()
  end subroutine test1

  subroutine test2
    use B
    use A
    implicit none
    type(a_type) :: a_type_instance
    type(b_type) :: b_type_instance

    print *, a_type_instance%sizeReturn()
    print *, b_type_instance%sizeReturn()
  end subroutine test2
end program main


! { dg-do run }
!
! PR fortran/45900
! The BTYPEINSTANCE%CALLBACK() typebound call was resolved incorrectly to
! A's CALLBACK procedure instead of B's because the CALLBACK name is ambiguous
! in the MAIN namespace.
!
! Original testcase by someone <ort...@gmail.com>

module A
implicit none
    type :: aType
    contains
        procedure :: callback
    end type aType
    contains
        subroutine callback( callback_, i )
            implicit none
            class(aType) :: callback_
            integer :: i

            i = 3
        end subroutine callback

        subroutine solver( callback_, i )
            implicit none
            class(aType) :: callback_
            integer :: i

            call callback_%callback(i)
        end subroutine solver
end module A

module B
use A, only: aType
implicit none
    type, extends(aType) :: bType
        integer :: i
    contains
        procedure :: callback
    end type bType
    contains
        subroutine callback( callback_, i )
            implicit none
            class(bType) :: callback_
            integer :: i

            i = 7
        end subroutine callback
end module B

program main
  call test1()
  call test2()

contains

  subroutine test1
    use A
    use B
    implicit none
    type(aType) :: aTypeInstance
    type(bType) :: bTypeInstance
    integer :: iflag

    bTypeInstance%i = 4

    iflag = 0
    call bTypeInstance%callback(iflag)
    if (iflag /= 7) call abort
    iflag = 1
    call solver( bTypeInstance, iflag )
    if (iflag /= 7) call abort

    iflag = 2
    call aTypeInstance%callback(iflag)
    if (iflag /= 3) call abort
  end subroutine test1

  subroutine test2
    use B
    use A
    implicit none
    type(aType) :: aTypeInstance
    type(bType) :: bTypeInstance
    integer :: iflag

    bTypeInstance%i = 4

    iflag = 0
    call bTypeInstance%callback(iflag)
    if (iflag /= 7) call abort
    iflag = 1
    call solver( bTypeInstance, iflag )
    if (iflag /= 7) call abort

    iflag = 2
    call aTypeInstance%callback(iflag)
    if (iflag /= 3) call abort
  end subroutine test2
end program main


Reply via email to