Another OOP problem found by Salvatore. Jim Xia confirms that NAG f95 gives the correct result, cf. http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/e18d0434c46598e2 "The GENERIC is Fortran is designed as such that the invocation is resolved at compile time to a specific binding. In your case, af2%do() and af2%get() both are solved to call binding a2f%doit() and af2%getit(). These two calls are equivalent to af2%doit() and af2%getit(). And based on the dynamic type of af2, routines doit2() and getit2() are both called." The following program shows (GCC trunk after fortran-dev merge): FOO%DOIT base version Getit value : 1 Expect result (as with NAG): FOO2%DOIT derived version Getit value : 3 This result is also obtained with gfortran if lines with "!!$" are uncommented - which is also the result with NAG f95 5.2. (NAG v5.1 rejects the latter code with a seemingly bogus "ambiguous specific type-bound procedures".) ! ------------------- testd15.f03---------------- module foo_mod type foo integer :: i contains procedure, pass(a) :: doit procedure, pass(a) :: getit generic, public :: do => doit generic, public :: get => getit end type foo private doit,getit contains subroutine doit(a) class(foo) :: a a%i = 1 write(*,*) 'FOO%DOIT base version' end subroutine doit function getit(a) result(res) class(foo) :: a integer :: res res = a%i end function getit end module foo_mod module foo2_mod use foo_mod type, extends(foo) :: foo2 integer :: j contains procedure, pass(a) :: doit => doit2 procedure, pass(a) :: getit => getit2 !!$ generic, public :: do => doit !!$ generic, public :: get => getit end type foo2 private doit2, getit2 contains subroutine doit2(a) class(foo2) :: a a%i = 2 a%j = 3 write(*,*) 'FOO2%DOIT derived version' end subroutine doit2 function getit2(a) result(res) class(foo2) :: a integer :: res res = a%j end function getit2 end module foo2_mod program testd15 use foo2_mod type(foo2) :: af2 call af2%do() write(*,*) 'Getit value : ', af2%get() end program testd15
(In reply to comment #0) > Another OOP problem found by Salvatore. > > Whoa, you beat me in opening the bug!
"4.5.7.3 Type-bound procedure overriding" (F2008 FDIS): "If a specific type-bound procedure specified in a type definition has the same binding name as a type-bound procedure from the parent type then the binding specified in the type definition overrides the one from the parent type." "If a generic binding specified in a type definition has the same generic-spec as an inherited binding, it extends the generic interface and shall satisfy the requirements specified in 12.4.3.4.5." "A binding of a type and a binding of an extension of that type correspond if the latter binding is the same binding as the former, overrides a corresponding binding, or is an inherited corresponding binding."
(In reply to comment #1) > (In reply to comment #0) > > Another OOP problem found by Salvatore. > > > > > Whoa, you beat me in opening the bug! > If I modify the source code as in the next attachment, I get an ICE (nice, since I was going to cut another source for the same problem, and now I can save the effort). Do you want me to open a separate PR?
Created attachment 20522 [details] test case
(In reply to comment #3) > (In reply to comment #1) > > (In reply to comment #0) > > > Another OOP problem found by Salvatore. > > > > > > > > Whoa, you beat me in opening the bug! > > > If I modify the source code as in the next attachment, I get an ICE (nice, > since I was going to cut another source for the same problem, and now I can > save the effort). > Do you want me to open a separate PR? > And the ICE in full glory... [sfilippo@donald bug15]$ gfortran -v Using built-in specs. COLLECT_GCC=gfortran COLLECT_LTO_WRAPPER=/usr/local/gnu46/libexec/gcc/x86_64-unknown-linux-gnu/4.6.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran,lto --no-create --no-recursion : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran,lto --no-create --no-recursion : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran,lto --no-create --no-recursion : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran,lto --no-create --no-recursion Thread model: posix gcc version 4.6.0 20100430 (experimental) (GCC) [sfilippo@donald bug15]$ gfortran -o testd15 testd15.f03 testd15.f03:73:0: internal compiler error: in gfc_add_component_ref, at fortran/expr.c:703 Please submit a full bug report, with preprocessed source if appropriate. See <http://gcc.gnu.org/bugs.html> for instructions.
(In reply to comment #0) > Another OOP problem found by Salvatore. > > Jim Xia confirms that NAG f95 gives the correct result, cf. > http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/e18d0434c46598e2 > > "The GENERIC is Fortran is designed as such that the invocation is resolved at > compile time to a specific binding. In your case, af2%do() and af2%get() both > are solved to call binding a2f%doit() and af2%getit(). These two calls are > equivalent to af2%doit() and af2%getit(). And based on the dynamic type of > af2, routines doit2() and getit2() are both called." This presumably applies to operators? I sincerely hope so because this will make life MUCH easier. Cheers Paul
I do not see any reason not to confirm this one. This Index: gcc/fortran/resolve.c =================================================================== *** gcc/fortran/resolve.c (revision 158958) --- gcc/fortran/resolve.c (working copy) *************** resolve_typebound_generic_call (gfc_expr *** 5132,5137 **** --- 5132,5138 ---- { gfc_typebound_proc* genproc; const char* genname; + gfc_symtree *st; gcc_assert (e->expr_type == EXPR_COMPCALL); genname = e->value.compcall.name; *************** resolve_typebound_generic_call (gfc_expr *** 5199,5204 **** --- 5200,5214 ---- return FAILURE; success: + genname = e->value.compcall.tbp->u.specific->name; + if (*genname == '@') + genname = e->value.compcall.tbp->u.specific->n.sym->name; + + st = gfc_find_typebound_proc (e->symtree->n.sym->ts.u.derived, NULL, + genname, false, &e->where); + if (st) + e->value.compcall.tbp = st->n.tb; + return SUCCESS; } is a fix for the first testcase - the only regression is dynamic_dispatch_5.f03, which needs dealing with in the same way as the fix for its PR; ie. the derived type needs to be that of the final reference. I'll have something ready by the end of the weekend. Paul
Created attachment 20571 [details] Fix for the PR Boostraps and regtests on RHEL5.4/i686 Will add testcase and ChangeLogs tomorrow. Paul
Subject: Bug 43945 Author: janus Date: Sun Jun 6 02:04:04 2010 New Revision: 160335 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=160335 Log: 2010-06-05 Paul Thomas <pault@gcc.gnu.org> Janus Weil <janus@gcc.gnu.org> PR fortran/43945 * resolve.c (get_declared_from_expr): Move to before resolve_typebound_generic_call. Make new_ref and class_ref ignorable if set to NULL. (resolve_typebound_generic_call): Once we have resolved the generic call, check that the specific instance is that which is bound to the declared type. (resolve_typebound_function,resolve_typebound_subroutine): Avoid freeing 'class_ref->next' twice. 2010-06-05 Paul Thomas <pault@gcc.gnu.org> PR fortran/43945 * gfortran.dg/generic_23.f03: New test. Added: trunk/gcc/testsuite/gfortran.dg/generic_23.f03 Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/resolve.c trunk/gcc/testsuite/ChangeLog
Comment #0 is fixed by r160335, but the ICE in comment #4 is still there.
Reduced test case for comment #4: module foo_mod type foo contains procedure, pass(a) :: doit generic :: do => doit end type contains subroutine doit(a) class(foo) :: a end subroutine end module module bar_mod contains subroutine dodo(a) use foo_mod class(foo) :: a call a%do() end subroutine end module program testd15 use foo_mod type(foo) :: af_ab call af_ab%do() end program testd15.f03:10:0: internal compiler error: in gfc_add_component_ref, at fortran/class.c:77
(In reply to comment #11) > Reduced test case for comment #4: Even further reduced: module foo_mod type foo contains procedure :: doit generic :: do => doit end type contains subroutine doit(a) class(foo) :: a end subroutine end module program testd15 contains subroutine dodo(x) use foo_mod class(foo) :: x call x%do() end subroutine end
The remaining issue (comment #4/#11/#12) is being tracked by PR 44434, so this one can be closed.
(In reply to comment #13) > The remaining issue (comment #4/#11/#12) is being tracked by PR 44434, so this > one can be closed. > The attached variation of generic_23 still does not work. [sfilippo@donald bug15]$ gfortran -v Using built-in specs. COLLECT_GCC=gfortran COLLECT_LTO_WRAPPER=/usr/local/gnu46/libexec/gcc/x86_64-unknown-linux-gnu/4.6.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran Thread model: posix gcc version 4.6.0 20100606 (experimental) (GCC) [sfilippo@donald bug15]$ gfortran -o generic_23_1 generic_23_1.f03 [sfilippo@donald bug15]$ ./generic_23_1 FOO%DOIT base version Abortito
Created attachment 20853 [details] test case
(In reply to comment #14) > The attached variation of generic_23 still does not work. > > [sfilippo@donald bug15]$ ./generic_23_1 > FOO%DOIT base version Aborted (core dumped) (In reply to comment #15) > Created an attachment (id=20853) [edit] REOPEN as the issue of the attachment is different from PR 44434; it uses allocatable scalars and might be thus yet another problem.
(In reply to comment #16) > (In reply to comment #14) > > The attached variation of generic_23 still does not work. > > > > [sfilippo@donald bug15]$ ./generic_23_1 > > FOO%DOIT base version > Aborted (core dumped) > > (In reply to comment #15) > > Created an attachment (id=20853) [edit] > > REOPEN as the issue of the attachment is different from PR 44434; it uses > allocatable scalars and might be thus yet another problem. > I should probably add that in my full code I am seeing failures in cases where the variable is not allocatable (i.e. similar to the already existing tests in generic_23). There is something very fishy here..... Salvatore
(In reply to comment #17) Dear All, The attached source file contains the same kind of test as the original testd15, and yet it fails. So, there's something missing from the patch, even without considering the allocatable issue; perhaps in producing the original test case I reduced a bit too much, and a more complicated example still fails. By the same token, I dared not reduce the new test case below its current size. compiling and running gives the following: [sfilippo@localhost bug15]$ gfortran -v Using built-in specs. COLLECT_GCC=gfortran COLLECT_LTO_WRAPPER=/home/local/gnu46/bin/../libexec/gcc/i686-pc-linux-gnu/4.6.0/lto-wrapper Target: i686-pc-linux-gnu Configured with: ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran : (reconfigured) ../gcc/configure --prefix=/usr/local/gnu46 --enable-languages=c,c++,fortran Thread model: posix gcc version 4.6.0 20100612 (experimental) (GCC) [sfilippo@localhost bug15]$ gfortran -o test_coo test_coo.f03 [sfilippo@localhost bug15]$ ./test_coo Error: Missing ovverriding impl for allocate in class COO
Created attachment 20927 [details] test-case
(In reply to comment #14) > The attached variation of generic_23 still does not work. ... and the dump shows why: if (vtab$foo2.get == 0B) { vtab$vtype$foo2$get.getit = getit; vtab$foo2.get = &vtab$vtype$foo2$get; vtab$foo2.getit = (integer(kind=4) (*<T42b>) (void)) getit2; vtab$foo2.doit = (void (*<T62>) (void)) doit2; vtab$vtype$foo2$do.doit = doit; vtab$foo2.do = &vtab$vtype$foo2$do; } The specific PPCs of 'foo2' point to the right procedures, but their generic counterparts don't.
(In reply to comment #20) > (In reply to comment #14) > > The attached variation of generic_23 still does not work. > > ... and the dump shows why: > > > > The specific PPCs of 'foo2' point to the right procedures, but their generic > counterparts don't. > Same thing happens for the code of #19: struct class$base_sparse_mat class.6; if (vtab$d_coo_sparse_mat.allocate == 0B) { vtab$vtype$d_coo_sparse_mat$allocate.allocate_mnnz = base_allocate_mnnz; vtab$d_coo_sparse_mat.allocate = &vtab$vtype$d_coo_sparse_mat$allocate; vtab$d_coo_sparse_mat.allocate_mnnz = (void (*<T5b>) (void)) d_coo_allocate_mnnz; vtab$d_coo_sparse_mat.set_null = (void (*<T5b>) (void)) base_set_null; vtab$d_coo_sparse_mat.get_fmt = (void (*<T5b>) (void)) d_coo_get_fmt; } class.6.$vptr = (struct vtype$base_sparse_mat *) &vtab$d_coo_sparse_mat; class.6.$data = (struct base_sparse_mat *) &acoo; base_allocate_mnnz (&n, &n, &class.6, &nnz); ^^^^^^^^^ Note the last statement should ultimately be resolved to vtab$d_coo_sparse_mat.allocate_mnnz
(In reply to comment #21) Ok, I bit the bullet, and fooled around with the internals to see what was happening. I did a very naive thing of adding warnings in resolve.c:resolve_typebound_generic_call, and I think I have found at least one thing differentiating generic_23 from test_coo above (this is the static example, not the allocatable one). The "fixed name" thing comes from the snippet of code success: /* Make sure that we have the right specific instance for the name. */ genname = e->value.compcall.tbp->u.specific->name; --------------------------- [sfilippo@donald bug15]$ gfortran -c test_coo.f03 Warning: Matched Name: '---' genname 'allocate' Warning: Fixed Name: '---' genname 'base_allocate_mnnz' --------------------------------- As you can see, the name is resolved to the specific procedure. The declaration was type :: base_sparse_mat integer, private :: m, n integer, private :: state, duplicate logical, private :: triangle, unitd, upper, sorted contains procedure, pass(a) :: get_fmt => base_get_fmt procedure, pass(a) :: set_null => base_set_null procedure, pass(a) :: allocate_mnnz => base_allocate_mnnz generic, public :: allocate => allocate_mnnz end type base_sparse_mat So the generics resolution is homing in to the procedure name. However my copy of the Fortran 2003 handbook says (at pages 95-97): 1. Specifinc bindings: PROCEDURE [ [,NON-OVERRIDABLE] [, binding-attribute-list] ::] binding-name [ => procedure-name ] 2. Generic bindings: GENERIC [ , access-spec ] :: generic-spec => binding-name-list Looks to me the existing mechanism is NOT doing the correct thing, as it should home on the BINDING-NAME (allocate_mnnz) and not on the procedure name (base_allocate_mnnz) Hope this will help in fixing this thing; as of now, I have no idea if this is related to the allocatable case (see my attachment generic_23_1) Salvatore
(In reply to comment #22) > generic_23.f03 obviously works becase the binding name DOIT and the procedure name are one and the same....
(In reply to comment #23) > (In reply to comment #22) > > > generic_23.f03 obviously works becase the binding name DOIT and the procedure > name are one and the same.... > Hi all Another variation to the test case, to have the guilty statements in a one-line function of their own, and the -fdump-tree-original shows what's going on: tryset is correct, tryall has this "a->$vptr->allocate->allocate_mnnz " thing which leads to error. If it was just "a->$vptr->allocate_mnnz " (which I tested by changing the statement to invoke directly the specific binding name) it would work. So, it looks like the code that resolves the generic procedure would do well to just avoid the GENERIC part of the vtab, resolve the generic to a specific and invoke the vtab for the specific. I have tried to follow the resolve code, but I got lost (I guess it's a bit coplex as a first trip inside gfortran guts :-) I suppose the originator(s) of the code would do much better. tryall (struct class$d_base_sparse_mat & restrict a, integer(kind=4) & restrict m, integer(kind=4) & restrict n, integer(kind=4) & restrict nz) { a->$vptr->allocate->allocate_mnnz ((integer(kind=4) *) m, (integer(kind=4) *) n, (struct class$d_base_sparse_mat *) a, (integer(kind=4) *) nz); } tryset (struct class$d_base_sparse_mat & restrict a) { a->$vptr->set_null ((struct class$d_base_sparse_mat *) a); }
Created attachment 21101 [details] test case
(In reply to comment #25) This fixes test_vt2 but not test_coo. Will keep investigating.....(and of course it should be done for functions as well as subroutines...) Index: gcc/fortran/resolve.c =================================================================== --- gcc/fortran/resolve.c (revisione 161820) +++ gcc/fortran/resolve.c (copia locale) @@ -5593,7 +5593,7 @@ gfc_symbol *vtab; vtab = gfc_find_derived_vtab (declared, true); gcc_assert (vtab); - gfc_add_component_ref (code->expr1, genname); + /* gfc_add_component_ref (code->expr1, genname); */ } gfc_add_component_ref (code->expr1, name);
(In reply to comment #26) For the test_coo.f03 case, what happens is shown in the following dump. { struct class$base_sparse_mat class.6; if (vtab$d_coo_sparse_mat.allocate == 0B) { vtab$d_coo_sparse_mat.allocate_mnnz = (void (*<T62>) (void)) d_coo_allocate_mnnz; vtab$d_coo_sparse_mat.set_null = (void (*<T62>) (void)) d_coo_set_null; vtab$d_coo_sparse_mat.get_fmt = (void (*<T62>) (void)) d_coo_get_fmt; } class.6.$vptr = (struct vtype$base_sparse_mat * {ref-all}) &vtab$d_coo_sparse_mat; class.6.$data = (struct base_sparse_mat *) &acoo; base_allocate_mnnz (&n, &n, &class.6, &nnz); } At the end of the block, since the type of acoo is known at compile time, the call gets resolved to base_allocate_mnnz, instead of resolving to vtab$d_coo_sparse_mat.allocate_mnnz which would contain the correct function. As shown in test_vt2, when the dynamic type is not known at compile time the naive diff I posted works. What happens in the code is that when the compiler enters this function static gfc_try resolve_typebound_static (gfc_expr* e, gfc_symtree** target, gfc_actual_arglist** actual) { gcc_assert (e->expr_type == EXPR_COMPCALL); gcc_assert (!e->value.compcall.tbp->is_generic); /* Update the actual arglist for PASS. */ if (update_compcall_arglist (e) == FAILURE) return FAILURE; *actual = e->value.compcall.actual; *target = e->value.compcall.tbp->u.specific; gfc_free_ref_list (e->ref); e->ref = NULL; e->value.compcall.actual = NULL; return SUCCESS; } we have (gdb) print *(e->value.compcall.tbp->u.specific) $7 = {priority = 3856, left = 0x0, right = 0x0, name = 0x7ffff1ae24c8 "base_allocate_mnnz", ambiguous = 0, n = {sym = 0x13c6580, uop = 0x13c6580, common = 0x13c6580, tb = 0x13c6580}} instead of pointing to the correct d_coo_allocate_mnnz (to which the vtab is correctly pointing). I have nowhere near enough knowledge of the code to conceive a fix, hopefully someone knowledgeable will take up.. Moreover, there still is the issue of initializing CLASS allocatables (see generic_23_1.f03) where it appears that something is missing after (sourced) allocation.
I'll take over this one. Have a fix.
Subject: Bug 43945 Author: janus Date: Tue Jul 13 06:57:17 2010 New Revision: 162125 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=162125 Log: 2010-07-13 Janus Weil <janus@gcc.gnu.org> PR fortran/44434 PR fortran/44565 PR fortran/43945 PR fortran/44869 * gfortran.h (gfc_find_derived_vtab): Modified prototype. * class.c (gfc_build_class_symbol): Modified call to 'gfc_find_derived_vtab'. (add_proc_component): Removed, moved code into 'add_proc_comp'. (add_proc_comps): Renamed to 'add_proc_comp', removed treatment of generics. (add_procs_to_declared_vtab1): Removed unnecessary argument 'resolved'. Removed treatment of generics. (copy_vtab_proc_comps): Removed unnecessary argument 'resolved'. Call 'add_proc_comp' instead of duplicating code. (add_procs_to_declared_vtab): Removed unnecessary arguments 'resolved' and 'declared'. (add_generic_specifics,add_generics_to_declared_vtab): Removed. (gfc_find_derived_vtab): Removed unnecessary argument 'resolved'. Removed treatment of generics. * iresolve.c (gfc_resolve_extends_type_of): Modified call to 'gfc_find_derived_vtab'. * resolve.c (resolve_typebound_function,resolve_typebound_subroutine): Removed treatment of generics. (resolve_select_type,resolve_fl_derived): Modified call to 'gfc_find_derived_vtab'. * trans-decl.c (gfc_get_symbol_decl): Ditto. * trans-expr.c (gfc_conv_derived_to_class,gfc_trans_class_assign): Ditto. * trans-stmt.c (gfc_trans_allocate): Ditto. 2010-07-13 Janus Weil <janus@gcc.gnu.org> PR fortran/44434 PR fortran/44565 PR fortran/43945 PR fortran/44869 * gfortran.dg/dynamic_dispatch_1.f03: Fixed invalid test case. * gfortran.dg/dynamic_dispatch_2.f03: Ditto. * gfortran.dg/dynamic_dispatch_3.f03: Ditto. * gfortran.dh/typebound_call_16.f03: New. * gfortran.dg/typebound_generic_6.f03: New. * gfortran.dg/typebound_generic_7.f03: New. * gfortran.dg/typebound_generic_8.f03: New. Added: trunk/gcc/testsuite/gfortran.dg/typebound_call_16.f03 trunk/gcc/testsuite/gfortran.dg/typebound_generic_6.f03 trunk/gcc/testsuite/gfortran.dg/typebound_generic_7.f03 trunk/gcc/testsuite/gfortran.dg/typebound_generic_8.f03 Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/class.c trunk/gcc/fortran/gfortran.h trunk/gcc/fortran/iresolve.c trunk/gcc/fortran/resolve.c trunk/gcc/fortran/trans-decl.c trunk/gcc/fortran/trans-expr.c trunk/gcc/fortran/trans-stmt.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/gfortran.dg/dynamic_dispatch_1.f03 trunk/gcc/testsuite/gfortran.dg/dynamic_dispatch_2.f03 trunk/gcc/testsuite/gfortran.dg/dynamic_dispatch_3.f03
Most test cases seem to be fixed, except of: (In reply to comment #19) > Created an attachment (id=20927) [edit] test-case Which shows with crayftn: Allocated COO succesfully, should now set components STOP but with gfortran: Error: Missing ovverriding impl for allocate in class COO
(In reply to comment #30) > Most test cases seem to be fixed, except of: > > (In reply to comment #19) > > Created an attachment (id=20927) [edit] test-case > > Which shows with crayftn: > > Allocated COO succesfully, should now set components > STOP > > but with gfortran: > > Error: Missing ovverriding impl for allocate in class COO > Yup, but after discussion with Janus, it seems the failing part is not dynamic dispatching, but compile-time resolution. Accordingly, I have appended the test case to PR 42385. Salvatore
(In reply to comment #31) > Yup, but after discussion with Janus, it seems the failing part is not dynamic > dispatching, but compile-time resolution. Accordingly, I have appended the test > case to PR 42385. OK. We can thus close this PR. By the way, instead of attaching the file multiple times, you can simply type "attachment <number>" Bugzilla then automatically changes this into a link (cf. e.g. comment 30).