Bug 51995

Summary: [OOP] Polymorphic class fails at runtime
Product: gcc Reporter: Prince <jilfa12>
Component: fortranAssignee: Tobias Burnus <burnus>
Status: RESOLVED FIXED    
Severity: normal CC: burnus, janus
Priority: P3 Keywords: rejects-valid
Version: 4.7.0   
Target Milestone: 4.7.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2012-01-25 00:00:00
Attachments: A factory pattern design to illustrate class pointers (polymorphic) behavior

Description Prince 2012-01-25 10:28:14 UTC
Created attachment 26458 [details]
A factory pattern design to illustrate class pointers (polymorphic) behavior

The attached factory pattern compiled successfully.

1    PROGRAM main
2
3     USE factory_pattern
4
5     IMPLICIT NONE
6
7     TYPE(CFactory) :: factory
8     CLASS(Connection), POINTER :: db_connect => NULL()
9
10    CALL factory%init("Oracle")
11    db_connect => factory%create_connection()   !! Create Oracle DB
12    CALL db_connect%description()
13
14    !! The same factory can be used to create different connections
15    CALL factory%init("MySQL")                  !! Create MySQL DB
16
17    !! 'connect' is a 'class' pointer. So can be used for either Oracle or  MySQL
18    db_connect => factory%create_connection()
19    CALL db_connect%description()
20
21    CALL factory%finalize()        ! Destroy the object
22
23   END PROGRAM main


The test driver program above produced this error when compiled with gfortran-4.7.0:

test_factory.f90:12.29:

  CALL db_connect%description()
                             1
Error: 'description' at (1) is not a member of the 'connection' structure
test_factory.f90:19.29:

  CALL db_connect%description()
                             1
Error: 'description' at (1) is not a member of the 'connection' structure


The program (according to http://fortranwiki.org/fortran/show/Factory+Pattern) apparently run successfully with gfortran-4.6.0.

Is this a bug?
Comment 1 Dominique d'Humieres 2012-01-25 10:59:09 UTC
I confirm that on x86_64-apple-darwin10 from
gcc version 4.6.0 20100723 (experimental) [trunk revision 162456] (GCC) up to now,
gfortran gives the following errors for the test

pr51995.f90:91.31:

    CALL db_connect%description()
                               1
Error: 'description' at (1) is not a member of the 'connection' structure
pr51995.f90:98.31:

    CALL db_connect%description()
                               1
Error: 'description' at (1) is not a member of the 'connection' structure

while up to
gcc version 4.6.0 20100413 (experimental) [trunk revision 158252] (GCC)
it gives

pr51995.f90:15.28:

     PROCEDURE(generic_desc), DEFERRED, PASS(self) :: description
                            1
Error: Passed-object dummy argument of 'generic_desc' at (1) must not be POINTER
pr51995.f90:82.23:

    USE factory_pattern
                       1
Fatal Error: Can't open module file 'factory_pattern.mod' for reading at (1): No such file or directory

Also gcc version 4.6.0 20100506 (experimental) [trunk revision 159106] (GCC) gives

f951: internal compiler error: in find_typebound_proc_uop, at fortran/symbol.c:5255
Please submit a full bug report,

So if it has worked, it looks like a transient.
Comment 2 Tobias Burnus 2012-01-25 11:05:41 UTC
Using today's GCC 4.7 and using one one-week-old one, it compiles without any error.

It seems as if the bug has been already fixed - or it only affects certain architectures. Can you provide more details about the used GCC version ("gfortran -v")? You should also try a newer version and check whether the issue still occurs.
Comment 3 Tobias Burnus 2012-01-25 11:11:18 UTC
(In reply to comment #1)
> I confirm that on x86_64-apple-darwin10 from
> gcc version 4.6.0 20100723 (experimental) [trunk revision 162456] (GCC) up to
> now, gfortran gives the following errors

Hmm, it also works for me (on x86_64-unknown-linux-gnu) with
  4.6.3 20111212 [gcc-4_6-branch revision 182222]
  4.6.3 20120121 [gcc-4_6-branch revision 183121]

I tried running gfortran through valgrind (4.7 and 4.6) but that only shows memory leakage.

As it does not fail for me, I cannot debug it, sorry.
Comment 4 Prince 2012-01-25 11:16:29 UTC
Thanks Dominiq.

I tested the program on i686 GNU/Linux running on Ubuntu-Maverick using gcc version 4.7.0 20120118 (experimental) (GCC).

Using ifort 12, it gives the correct results.

So it is definitely a bug in gfortran. Do you have any work-around?



________________________________
 From: dominiq at lps dot ens.fr <gcc-bugzilla@gcc.gnu.org>
To: jilfa12@yahoo.com 
Sent: Wednesday, January 25, 2012 12:59 PM
Subject: [Bug fortran/51995] Polymorphic class fails at runtime
 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51995

--- Comment #1 from Dominique d'Humieres <dominiq at lps dot ens.fr> 2012-01-25 10:59:09 UTC ---
I confirm that on x86_64-apple-darwin10 from
gcc version 4.6.0 20100723 (experimental) [trunk revision 162456] (GCC) up to
now,
gfortran gives the following errors for the test

pr51995.f90:91.31:

    CALL db_connect%description()
                               1
Error: 'description' at (1) is not a member of the 'connection' structure
pr51995.f90:98.31:

    CALL db_connect%description()
                               1
Error: 'description' at (1) is not a member of the 'connection' structure

while up to
gcc version 4.6.0 20100413 (experimental) [trunk revision 158252] (GCC)
it gives

pr51995.f90:15.28:

     PROCEDURE(generic_desc), DEFERRED, PASS(self) :: description
                            1
Error: Passed-object dummy argument of 'generic_desc' at (1) must not be
POINTER
pr51995.f90:82.23:

    USE factory_pattern
                       1
Fatal Error: Can't open module file 'factory_pattern.mod' for reading at (1):
No such file or directory

Also gcc version 4.6.0 20100506 (experimental) [trunk revision 159106] (GCC)
gives

f951: internal compiler error: in find_typebound_proc_uop, at
fortran/symbol.c:5255
Please submit a full bug report,

So if it has worked, it looks like a transient.
Comment 5 Tobias Burnus 2012-01-25 11:17:38 UTC
Ignore that. I missed that one needs *both* the attachment and the program. Thus, I can actually reproduce it.  Sorry for the pilot error.

Thus, I am able to reproduce it both with 4.5, 4.6 and 4.7. (The program compiles with ifort 12.1 - and at a glance, I cannot spot anything which looks invalid.)
Comment 6 Prince 2012-01-25 11:20:58 UTC
Thanks for the prompt reply.

I tested the program on i686 GNU/Linux running on Ubuntu-Maverick using gcc version 4.7.0 20120118 (experimental) (GCC).



________________________________
 From: burnus at gcc dot gnu.org <gcc-bugzilla@gcc.gnu.org>
To: jilfa12@yahoo.com 
Sent: Wednesday, January 25, 2012 1:05 PM
Subject: [Bug fortran/51995] Polymorphic class fails at runtime
 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51995

--- Comment #2 from Tobias Burnus <burnus at gcc dot gnu.org> 2012-01-25 11:05:41 UTC ---
Using today's GCC 4.7 and using one one-week-old one, it compiles without any
error.

It seems as if the bug has been already fixed - or it only affects certain
architectures. Can you provide more details about the used GCC version
("gfortran -v")? You should also try a newer version and check whether the
issue still occurs.
Comment 7 Tobias Burnus 2012-01-25 12:47:49 UTC
The problem seems to be the following:

One properly calls match_typebound_call, which sets "base" (alias "primary") to the symtree of "db_connect" (which is of type BT_CLASS). Then it calls:

gfc_match_varspec (primary=0x16cf3d0, equiv_flag=0, sub_flag=true, ppc_arg=true)

There, the problem is that one has:

  sym = sym->ts.u.derived;
  if (sym->f2k_derived)

But "sym" is only the class container. One needs sym->components->ts.u.derived->f2k_derived.


One could simply do:

--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -1911 +1911,2 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag,
-  sym = sym->ts.u.derived;
+  sym = (sym->ts.type == BT_CLASS) ? CLASS_DATA (sym)->ts.u.derived
+                                  : sym->ts.u.derived;

But that will fail later with
internal compiler error: in gfc_conv_component_ref, at fortran/trans-expr.c:1100
Comment 8 Tobias Burnus 2012-01-25 13:29:48 UTC
(In reply to comment #4)
> I tested the program on i686 GNU/Linux running on Ubuntu-Maverick using gcc
> version 4.7.0 20120118 (experimental) (GCC).
> 
> So it is definitely a bug in gfortran. Do you have any work-around?

Unfortunately, I am not aware of a workaround. I have to admit that I have not fully understood why fclass->f2k_derived gets often but not always set.

However, the following patch works. Thus, you could either apply it and build your own GCC, or you wait a day after the committal and get a nightly build at http://gcc.gnu.org/wiki/GFortranBinaries - or you convince Matthias to do a new Ubuntu build.


(In reply to comment #7)
> There, the problem is that one has:
>   sym = sym->ts.u.derived;
>   if (sym->f2k_derived)

Actually, f2k_derived should also get set for the class container.

Better patch (read: actually working) patch:

--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -421,6 +421,8 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
       c->attr.access = ACCESS_PRIVATE;
       c->attr.pointer = 1;
     }
+  else if (!fclass->f2k_derived)
+    fclass->f2k_derived = fclass->components->ts.u.derived->f2k_derived;

   /* Since the extension field is 8 bit wide, we can only have
      up to 255 extension levels.  */
Comment 9 Prince 2012-01-25 13:32:50 UTC
Using five days old gcc version 4.7.0 20120120 (experimental) (GCC), 
the problem still persists.

I think the problem has not been fixed for the i686 architecture.
Do you know of any work-around for this? 
Ifort 12.1 runs the program successfully without memory leak.


________________________________
 From: burnus at gcc dot gnu.org <gcc-bugzilla@gcc.gnu.org>
To: jilfa12@yahoo.com 
Sent: Wednesday, January 25, 2012 2:47 PM
Subject: [Bug fortran/51995] [OOP] Polymorphic class fails at runtime
 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51995

--- Comment #7 from Tobias Burnus <burnus at gcc dot gnu.org> 2012-01-25 12:47:49 UTC ---
The problem seems to be the following:

One properly calls match_typebound_call, which sets "base" (alias "primary") to
the symtree of "db_connect" (which is of type BT_CLASS). Then it calls:

gfc_match_varspec (primary=0x16cf3d0, equiv_flag=0, sub_flag=true,
ppc_arg=true)

There, the problem is that one has:

  sym = sym->ts.u.derived;
  if (sym->f2k_derived)

But "sym" is only the class container. One needs
sym->components->ts.u.derived->f2k_derived.


One could simply do:

--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -1911 +1911,2 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag,
-  sym = sym->ts.u.derived;
+  sym = (sym->ts.type == BT_CLASS) ? CLASS_DATA (sym)->ts.u.derived
+                                  : sym->ts.u.derived;

But that will fail later with
internal compiler error: in gfc_conv_component_ref, at
fortran/trans-expr.c:1100
Comment 10 Tobias Burnus 2012-01-25 17:34:48 UTC
Author: burnus
Date: Wed Jan 25 17:34:39 2012
New Revision: 183528

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=183528
Log:
2012-01-25  Tobias Burnus  <burnus@net-b.de>

        PR fortran/51995
        * class.c (gfc_build_class_symbol): Ensure that
        fclass->f2k_derived is set.

2012-01-25  Tobias Burnus  <burnus@net-b.de>

        PR fortran/51995
        * gfortran.dg/typebound_proc_25.f90: New.


Added:
    trunk/gcc/testsuite/gfortran.dg/typebound_proc_25.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/class.c
    trunk/gcc/testsuite/ChangeLog
Comment 11 Tobias Burnus 2012-01-25 17:41:44 UTC
FIXED on the trunk (4.7).

Thanks for the bug report! See comment 8 for how to obtain a newer version.
Comment 12 Dominique d'Humieres 2012-01-25 19:06:40 UTC
On x86_64-apple-darwin10 and an almost clean tree (i.e., with only the patch for pr 51985) at revision 183528, compiling testsuite/gfortran.dg/typebound_proc_25.f90 gives an ICE:

[macbook] f90/bug% gfcp /opt/gcc/work/gcc/testsuite/gfortran.dg/typebound_proc_25.f90
/opt/gcc/work/gcc/testsuite/gfortran.dg/typebound_proc_25.f90:88:0: internal compiler error: in gfc_release_symbol, at fortran/symbol.c:2531

instead of the errors (the same happens on my main patched tree).
Comment 13 Dominique d'Humieres 2012-01-25 20:23:02 UTC
Reduced test case exhibiting the ICE:

MODULE factory_pattern

  TYPE CFactory
     PRIVATE
     CHARACTER(len=20) :: factory_type      !! Descriptive name for database
     CLASS(Connection), POINTER :: connection_type !! Which type of database ?
   CONTAINS                                        !! Note 'class' not 'type' !
     PROCEDURE :: create_connection                !! Connect to database
  END TYPE CFactory

  TYPE, ABSTRACT :: Connection
   CONTAINS
     PROCEDURE(generic_desc), DEFERRED, PASS(self) :: description
  END TYPE Connection

  ABSTRACT INTERFACE
     SUBROUTINE generic_desc(self)
       IMPORT :: Connection
       CLASS(Connection), INTENT(in) :: self
     END SUBROUTINE generic_desc
  END INTERFACE

  !! An Oracle connection
  TYPE, EXTENDS(Connection) :: OracleConnection
   CONTAINS
     PROCEDURE, PASS(self) :: description => oracle_desc
  END TYPE OracleConnection

CONTAINS

  FUNCTION create_connection(self)  RESULT(ptr)
    CLASS(CFactory) :: self
    CLASS(Connection), POINTER :: ptr

  END FUNCTION create_connection

  SUBROUTINE oracle_desc(self)
    CLASS(OracleConnection), INTENT(in) :: self
  END SUBROUTINE oracle_desc

END MODULE factory_pattern
Comment 14 Tobias Burnus 2012-01-25 22:21:19 UTC
Author: burnus
Date: Wed Jan 25 22:21:14 2012
New Revision: 183541

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=183541
Log:
2012-01-25  Tobias Burnus  <burnus@net-b.de>

        PR fortran/51995
        * class.c (gfc_build_class_symbol): Fix invalid freeing
        issue with fclass->f2k_derived.


Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/class.c