User account creation filtered due to spam.

Bug 45271 - [OOP] Polymorphic code breaks when changing order of USE statements
Summary: [OOP] Polymorphic code breaks when changing order of USE statements
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: 4.6.0
Assignee: janus
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2010-08-12 19:55 UTC by Harald Anlauf
Modified: 2016-11-16 13:35 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-08-19 13:08:47


Attachments
Demo code (801 bytes, text/plain)
2010-08-12 19:56 UTC, Harald Anlauf
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Harald Anlauf 2010-08-12 19:55:13 UTC
Hi,

the attached code fails at runtime as follows:

% ./a.out
 calling cg...
 cg: before g%assign
 Oops in concrete_vector::my_assign : wrong type

Interchanging the indicated use statements in the main
program leads to:

% ./a.out
 calling cg...
 cg: before g%assign
 cg: after  g%assign
 after cg...

The code works flawlessly with nagfor 5.2,
xlf 12.1 and xlf 13.1.

Cheers,
ha
Comment 1 Harald Anlauf 2010-08-12 19:56:20 UTC
Created attachment 21471 [details]
Demo code
Comment 2 janus 2010-08-13 08:22:21 UTC
Confirmed.

-fdump-tree-original shows only one difference when exchanging the use statements:


--- c1.f90.003t.original        2010-08-13 10:05:17.720283742 +0200
+++ c1.f90.003t.original.bug    2010-08-13 10:04:53.912784753 +0200
@@ -215,7 +215,7 @@ MAIN__ ()
 
     if (vtab$trivial_gradient_type.assign == 0B)
       {
-        vtab$trivial_gradient_type.assign = my_assign;
+        vtab$trivial_gradient_type.assign = (void (*<T4a1>) (struct class$trivial_gradient_type & restrict, struct class$vector_class & restrict)) my_assign;
       }
     class.8.$vptr = (struct vtype$gradient_class * {ref-all}) &vtab$trivial_gradient_type;
     class.8.$data = (struct gradient_class *) &g_initial;
Comment 3 janus 2010-08-13 09:29:51 UTC
Here is a reduced test case:

module abstract_vector
  implicit none
  type, abstract :: vector_class
  contains
    procedure(op_assign_v_v), deferred :: assign
  end type vector_class
  abstract interface
    subroutine op_assign_v_v(this,v)
      import vector_class
      class(vector_class), intent(inout) :: this
      class(vector_class), intent(in)    :: v
    end subroutine
  end interface
end module abstract_vector

module concrete_vector
  use abstract_vector
  implicit none
  type, extends(vector_class) :: trivial_vector_type
  contains
    procedure :: assign => my_assign
  end type
contains
  subroutine my_assign (this,v)
    class(trivial_vector_type), intent(inout) :: this
    class(vector_class),        intent(in)    :: v
    write (*,*) 'Oops in concrete_vector::my_assign'
    call abort ()
  end subroutine
end module concrete_vector

module concrete_gradient
  use abstract_vector
  implicit none
  type, extends(vector_class) :: trivial_gradient_type
  contains
    procedure :: assign => my_assign
  end type
contains
  subroutine my_assign (this,v)
    class(trivial_gradient_type), intent(inout) :: this
    class(vector_class),          intent(in)    :: v
    write (*,*) 'concrete_gradient::my_assign'
  end subroutine
end module concrete_gradient

program main
  !--- exchange these two lines to make the code work:
  use concrete_vector    ! (1)
  use concrete_gradient  ! (2)
  !---
  implicit none
  type(trivial_gradient_type)      :: g_initial
  class(vector_class),  allocatable :: g
  print *, "cg: before g%assign"
  allocate(trivial_gradient_type :: g)
  call g%assign (g_initial)
  print *, "cg: after  g%assign"
end program main
Comment 4 janus 2010-08-13 09:50:00 UTC
The problem is the following:

We have two routines called 'my_assign' (in two different modules). When initializing the vtabs in the main program, we happen to use the wrong one:

      if (vtab$trivial_gradient_type.assign == 0B)
        {
          vtab$trivial_gradient_type.assign = my_assign;
        }


Possible solutions:
1) Make sure we use the right symbol from the right module.
2) Do the vtab initialization inside the module that defines the class, i.e. add a module procedure like 'vtab$trivial_gradient_type$init' which does it, and call this from the main program. Then there is no name ambiguity.
Comment 5 janus 2010-08-13 12:36:00 UTC
> We have two routines called 'my_assign' (in two different modules). When
> initializing the vtabs in the main program, we happen to use the wrong one:

This is because the 'f2k_derived' namespace of 'trivial_gradient_type' contains the wrong symbol for 'my_assign'. Apparently the symbols are mixed up when reading the module files.


The initialization of the vtab happens in gfc_trans_assign_vtab_procs (trans-expr.c).
Comment 6 Mikael Morin 2010-08-13 14:25:07 UTC
There is code to prevent duplicate names to be imported, but it is bypassed by vtab and vtype stuff:

in module.c line 4373: 

	  /* Exception: Always import vtabs & vtypes.  */
	  if (p == NULL && (strcmp (xstrndup (name,5), "vtab$") == 0
			    || strcmp (xstrndup (name,6), "vtype$") == 0))
	    p = name;

	  /* Skip symtree nodes not in an ONLY clause, unless there
	     is an existing symtree loaded from another USE statement.  */
	  if (p == NULL)
	    {
	      st = gfc_find_symtree (gfc_current_ns->sym_root, name);
	      if (st != NULL)
		info->u.rsym.symtree = st;
	      continue;
	    }
Comment 7 janus 2010-08-13 14:31:09 UTC
(In reply to comment #6)
> There is code to prevent duplicate names to be imported, but it is bypassed by
> vtab and vtype stuff:

This is fine. The problem is not in importing the vtab symbols, but importing the TBP targets (i.e. "my_assign" in the test case).
Comment 8 janus 2010-08-13 17:23:32 UTC
Actually I think it's a duplicate of PR42769, or at least related.
Comment 9 janus 2010-08-15 20:01:30 UTC
(In reply to comment #4)
> Possible solutions:
> 1) Make sure we use the right symbol from the right module.
> 2) Do the vtab initialization inside the module that defines the class, i.e.
> add a module procedure like 'vtab$trivial_gradient_type$init' which does it,
> and call this from the main program. Then there is no name ambiguity.
 
3) Do it in the original module (like in #2), but statically via default initialization. This is definitely the most elegant and efficient way. It should be possible once PR45290 is implemented.
Comment 10 janus 2010-08-19 13:08:47 UTC
(In reply to comment #9)
> (In reply to comment #4)
> > Possible solutions:
> > 1) Make sure we use the right symbol from the right module.
> > 2) Do the vtab initialization inside the module that defines the class, i.e.
> > add a module procedure like 'vtab$trivial_gradient_type$init' which does it,
> > and call this from the main program. Then there is no name ambiguity.
> 
> 3) Do it in the original module (like in #2), but statically via default
> initialization.

Mine. I'm working on a patch which implements solution #3. It already fixes the test case, but still has a few regresssions.
Comment 11 janus 2010-08-21 14:51:19 UTC
Subject: Bug 45271

Author: janus
Date: Sat Aug 21 14:50:57 2010
New Revision: 163445

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=163445
Log:
2010-08-21  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/45271
	PR fortran/45290
	* class.c (add_proc_comp): Add static initializer for PPCs.
	(add_procs_to_declared_vtab): Modified comment.
	* module.c (mio_component): Add argument 'vtype'. Don't read/write the
	initializer if the component is part of a vtype.
	(mio_component_list): Add argument 'vtype', pass it on to
	'mio_component'.
	(mio_symbol): Modified call to 'mio_component_list'.
	* trans.h (gfc_conv_initializer): Modified prototype.
	(gfc_trans_assign_vtab_procs): Removed.
	* trans-common.c (create_common): Modified call to
	'gfc_conv_initializer'.
	* trans-decl.c (gfc_get_symbol_decl,get_proc_pointer_decl,
	gfc_emit_parameter_debug_info): Modified call to
	'gfc_conv_initializer'.
	(build_function_decl): Remove assertion.
	* trans-expr.c (gfc_conv_derived_to_class,gfc_trans_class_assign):
	Removed call to 'gfc_trans_assign_vtab_procs'.
	(gfc_conv_initializer): Add argument 'procptr'.
	(gfc_conv_structure): Modified call to 'gfc_conv_initializer'.
	(gfc_trans_assign_vtab_procs): Removed.
	* trans-stmt.c (gfc_trans_allocate): Removed call to
	'gfc_trans_assign_vtab_procs'.


2010-08-21  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/44863
	PR fortran/45271
	PR fortran/45290
	* gfortran.dg/dynamic_dispatch_10.f03: New (PR 44863 comment #1).
	* gfortran.dg/pointer_init_5.f90: New (PR 45290 comment #6).
	* gfortran.dg/typebound_call_18.f03: New (PR 45271 comment #3).

Added:
    trunk/gcc/testsuite/gfortran.dg/dynamic_dispatch_10.f03
    trunk/gcc/testsuite/gfortran.dg/pointer_init_5.f90
    trunk/gcc/testsuite/gfortran.dg/typebound_call_18.f03
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/class.c
    trunk/gcc/fortran/module.c
    trunk/gcc/fortran/trans-common.c
    trunk/gcc/fortran/trans-decl.c
    trunk/gcc/fortran/trans-expr.c
    trunk/gcc/fortran/trans-stmt.c
    trunk/gcc/fortran/trans.h
    trunk/gcc/testsuite/ChangeLog

Comment 12 janus 2010-08-21 15:00:40 UTC
Fixed with r163445. Closing.