Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Mikael Morin wrote: On 29/08/2012 21:53, Tobias Burnus wrote: a) The main patch, which implements the wrapper. I am asking for approval for that patch. A few more nitpicks below. I would like to include the patch (c) as modifying the vtable changes the ABI. Bumping the .mod version is a reliable way to force recompilation. The alternative is to wait until the final FINAL patch before bumping the .mod version (and disable the "_final" generation). I don't like bumping the module version, for something not module-related (vtypes are output as normal types in the module files), but I guess it is the most user-friendly thing to do. I also do not like it - but it might otherwise lead to segfaults at run time (or the wrong procedure being called), which is even uglier. Is the patch (a) OK for the trunk? With which version of (c)? (I am slightly inclined to do the .mod bump now. As a follow up, one can also commit Janus' proc-pointer patch, http://gcc.gnu.org/ml/fortran/2012-04/msg00033.html, though I think someone has still to review it.) I am inclined to disable finalization completely (thus defer .mod bump), because the new code is hardly tested and doesn't provide (yet) new benefits such as reduced memory leaks as it is disabled. We could do the bump now, but I'm afraid that we discover a bug when finalization gets completely implemented, and we have to bump again to fix it (though I don't see what kind of bug it could be). I concur. I think Janus' patch is a much less serious problem in the sense that people trying to link codes compiled with patched and non-patched compiler will get a link error. I don't think it's worth a .mod bump. Well, the idea was: If we do bump the .mod for this patch, having around that time Janus' patch (which also breaks the ABI) makes sense. I concur that his ABI breakage is less severe. For (a), I noticed a few indenting issues (8+ spaces) and (mostly wording) nits below to be fixed. Then OK. Fixed. +/* Returns true if any of its nonpointer nonallocatable components or + their nonpointer nonallocatable subcomponents has a finalization + subroutine. */ + +static bool +has_finalizer_component (gfc_symbol *derived) Rename to has_finalizable_component ? I prefer finalizer because also allocatable components are finalizable but they are excluded by this check. +/* Call DEALLOCATE for the passed component if it is allocatable, if it is + neither allocatable nor a pointer but has a finalizer, call it. If it + is a nonpointer component with allocatable or finalizes components, walk s/finalizes/finalizable/ ? Actually: with allocatable components or has finalizers. + them. Either of the is required; other nonallocatables and pointers aren't s/the/them/ ? done. + handled gracefully. + Note: The DEALLOCATE handling takes care of finalizers, coarray + deregistering and allocatable components of the allocatable. */ "coarray deregistering and allocatable components" is confusing. Note: If the component is allocatable, the DEALLOCATE handling takes care of calling the appropriate finalizer(s), of coarray deregistering, and of deallocating allocatable (sub)components. Done. +/* Generate the wrapper finalization/polymorphic freeing subroutine for the Difficult to read. "Generate the finalization/polymorphic freeing wrapper subroutine..." or something ? Done. + /* We now create a wrapper, which does the following: + 1. It calls the suitable finalization subroutine for this type s/It calls/Call/ ? (to be in line with the other verbs). + 2. In a loop over all noninherited allocatable components and noninherited s/In a loop/Loop/ Done. Thanks for the review. I have no committed it as Rev. 190869 Tobias
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
On 29/08/2012 21:53, Tobias Burnus wrote: > Dear all, > > that's the revised version of patch at > http://gcc.gnu.org/ml/fortran/2012-08/msg00095.html, taking the review > comments into account. > > Reminder: This patch only generates the finalization wrapper, which is > in the virtual table. It does not add the required calls; hence, it > still doesn't allow to use finalization. > > > The patch consists of three parts: > > a) The main patch, which implements the wrapper. > I am asking for approval for that patch. A few more nitpicks below. > > b) A patch which removes the gfc_error "not yet implemented" > I suggest to only remove the error after finalization calls have been > added Sensible. By the way some (testsuite) parts of b) should be part of a). > > c) A patch which bumps the .mod version >- or alternatively - >a patch which disables the _final generation in the vtable. > > I have build and regtested (on x86-64-linux) the patch with (a) and > (a)+(b) applied. > > > I would like to include the patch (c) as modifying the vtable changes > the ABI. Bumping the .mod version is a reliable way to force > recompilation. The alternative is to wait until the final FINAL patch > before bumping the .mod version (and disable the "_final" generation). I don't like bumping the module version, for something not module-related (vtypes are output as normal types in the module files), but I guess it is the most user-friendly thing to do. > > One possibility, if deemed useful, is to combine the .mod version bump > with backward compatible reading of .mod files, i.e., only error out > when BT_CLASS is encountered in an old .mod file. Let's keep things simple, let's not do that. > > > Is the patch (a) OK for the trunk? With which version of (c)? > > (I am slightly inclined to do the .mod bump now. As a follow up, one can > also commit Janus' proc-pointer patch, > http://gcc.gnu.org/ml/fortran/2012-04/msg00033.html, though I think > someone has still to review it.) I am inclined to disable finalization completely (thus defer .mod bump), because the new code is hardly tested and doesn't provide (yet) new benefits such as reduced memory leaks as it is disabled. We could do the bump now, but I'm afraid that we discover a bug when finalization gets completely implemented, and we have to bump again to fix it (though I don't see what kind of bug it could be). I think Janus' patch is a much less serious problem in the sense that people trying to link codes compiled with patched and non-patched compiler will get a link error. I don't think it's worth a .mod bump. Unless I miss something. For (a), I noticed a few indenting issues (8+ spaces) and (mostly wording) nits below to be fixed. Then OK. > diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c > index 21a91ba..9d58aab 100644 > --- a/gcc/fortran/class.c > +++ b/gcc/fortran/class.c > @@ -689,6 +694,702 @@ copy_vtab_proc_comps (gfc_symbol *declared, gfc_symbol > *vtype) > } > > > +/* Returns true if any of its nonpointer nonallocatable components or > + their nonpointer nonallocatable subcomponents has a finalization > + subroutine. */ > + > +static bool > +has_finalizer_component (gfc_symbol *derived) Rename to has_finalizable_component ? > +{ > + gfc_component *c; > + > + for (c = derived->components; c; c = c->next) > +{ > + if (c->ts.type == BT_DERIVED && c->ts.u.derived->f2k_derived > + && c->ts.u.derived->f2k_derived->finalizers) > + return true; > + > + if (c->ts.type == BT_DERIVED > + && !c->attr.pointer && !c->attr.allocatable > + && has_finalizer_component (c->ts.u.derived)) > + return true; > +} > + return false; > +} > + > + > +/* Call DEALLOCATE for the passed component if it is allocatable, if it is > + neither allocatable nor a pointer but has a finalizer, call it. If it > + is a nonpointer component with allocatable or finalizes components, walk s/finalizes/finalizable/ ? > + them. Either of the is required; other nonallocatables and pointers aren't s/the/them/ ? > + handled gracefully. > + Note: The DEALLOCATE handling takes care of finalizers, coarray > + deregistering and allocatable components of the allocatable. */ "coarray deregistering and allocatable components" is confusing. Note: If the component is allocatable, the DEALLOCATE handling takes care of calling the appropriate finalizer(s), of coarray deregistering, and of deallocating allocatable (sub)components. > + > +static void > +finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp, > + gfc_expr *stat, gfc_code **code) [...] > + > + > +/* Generate the wrapper finalization/polymorphic freeing subroutine for the Difficult to read. "Generate the finalization/polymorphic freeing wrapper subroutine..." or something ? > + derived type "derived". The function first calls the approriate FINAL > + subroutine, then it DEALLOCATEs (finalizes/frees) the
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Dear all, that's the revised version of patch at http://gcc.gnu.org/ml/fortran/2012-08/msg00095.html, taking the review comments into account. Reminder: This patch only generates the finalization wrapper, which is in the virtual table. It does not add the required calls; hence, it still doesn't allow to use finalization. The patch consists of three parts: a) The main patch, which implements the wrapper. I am asking for approval for that patch. b) A patch which removes the gfc_error "not yet implemented" I suggest to only remove the error after finalization calls have been added c) A patch which bumps the .mod version - or alternatively - a patch which disables the _final generation in the vtable. I have build and regtested (on x86-64-linux) the patch with (a) and (a)+(b) applied. I would like to include the patch (c) as modifying the vtable changes the ABI. Bumping the .mod version is a reliable way to force recompilation. The alternative is to wait until the final FINAL patch before bumping the .mod version (and disable the "_final" generation). One possibility, if deemed useful, is to combine the .mod version bump with backward compatible reading of .mod files, i.e., only error out when BT_CLASS is encountered in an old .mod file. Is the patch (a) OK for the trunk? With which version of (c)? (I am slightly inclined to do the .mod bump now. As a follow up, one can also commit Janus' proc-pointer patch, http://gcc.gnu.org/ml/fortran/2012-04/msg00033.html, though I think someone has still to review it.) Tobias PS: When doing the ABI change, I am going to document it in the release notes / wiki. 2012-08-29 Alessandro Fanfarillo Tobias Burnus PR fortran/37336 * gfortran.h (symbol_attribute): Add artificial. * module.c (mio_symbol_attribute): Handle attr.artificial * class.c (gfc_build_class_symbol): Defer creation of the vtab if the DT has finalizers, mark generated symbols as attr.artificial. (has_finalizer_component, finalize_component, finalization_scalarizer, generate_finalization_wrapper): New static functions. (gfc_find_derived_vtab): Add _final component and call generate_finalization_wrapper. * dump-parse-tree.c (show_f2k_derived): Use resolved proc_tree->n.sym rather than unresolved proc_sym. (show_attr): Handle attr.artificial. * resolve.c (gfc_resolve_finalizers): Ensure that the vtab exists. (resolve_fl_derived): Resolve finalizers before generating the vtab. (resolve_symbol): Also allow assumed-rank arrays with CONTIGUOUS; skip artificial symbols. (resolve_fl_derived0): Skip artificial symbols. 2012-08-29 Tobias Burnus PR fortran/51632 * gfortran.dg/coarray_class_1.f90: New. diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c index 21a91ba..9d58aab 100644 --- a/gcc/fortran/class.c +++ b/gcc/fortran/class.c @@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see declared type of the class variable and its attributes (pointer/allocatable/dimension/...). * _vptr: A pointer to the vtable entry (see below) of the dynamic type. - + For each derived type we set up a "vtable" entry, i.e. a structure with the following fields: * _hash: A hash value serving as a unique identifier for this type. @@ -42,6 +42,9 @@ along with GCC; see the file COPYING3. If not see * _extends: A pointer to the vtable entry of the parent derived type. * _def_init: A pointer to a default initialized variable of this type. * _copy: A procedure pointer to a copying procedure. +* _final:A procedure pointer to a wrapper function, which frees + allocatable components and calls FINAL subroutines. + After these follow procedure pointer components for the specific type-bound procedures. */ @@ -572,7 +575,9 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr, if (gfc_add_component (fclass, "_vptr", &c) == FAILURE) return FAILURE; c->ts.type = BT_DERIVED; - if (delayed_vtab) + if (delayed_vtab + || (ts->u.derived->f2k_derived + && ts->u.derived->f2k_derived->finalizers)) c->ts.u.derived = NULL; else { @@ -689,6 +694,702 @@ copy_vtab_proc_comps (gfc_symbol *declared, gfc_symbol *vtype) } +/* Returns true if any of its nonpointer nonallocatable components or + their nonpointer nonallocatable subcomponents has a finalization + subroutine. */ + +static bool +has_finalizer_component (gfc_symbol *derived) +{ + gfc_component *c; + + for (c = derived->components; c; c = c->next) +{ + if (c->ts.type == BT_DERIVED && c->ts.u.derived->f2k_derived + && c->ts.u.derived->f2k_derived->finalizers) + return true; + + if (c->ts.type == BT_DERIVED + && !c->attr.pointer && !c->attr.allocatable + && has_finalizer_component (c->ts.u.derived)) + return true; +} + return false; +} + + +/* Call DEALLOCATE for the passed component if it is allocatable, if i
Re: [EXTERNAL] Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
On 27/08/2012 20:20, Rouson, Damian wrote: > Hi Mikael, > > Is this patch approved? There are a few overlooks to be fixed and the components walking code that I would like to see shared. Then I think it can go in. But there is no big stopper. Mikael
Re: [EXTERNAL] Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Hi Mikael, Is this patch approved? I realize it's not the final step (no pun intended), but I will be very excited to see this hit the trunk. Supporting FINAL will have broad impact on my work and the work of others writing modern Fortran libraries and applications. Damian On 8/25/12 1:42 PM, "Mikael Morin" wrote: >On 25/08/2012 22:06, Tobias Burnus wrote: > If comp has finalizable subcomponents, it has a finalization > wrapper, which is (or should be) caught above, so this branch > is (or should be) unreachable. I probably miss something, but I don't see why this branch should be unreachable. One has: if (component is allocatable) call DEALLOCATE(comp) ! which might invoke finalizers else if (component itself has a finalizer) call FINAL_WRAPPER else for all nonpointer subcomponents which are allocatables, have finalizers or have allocatable/finalizable components, call finalize_component. end if >>> I expected something like: if (allocatable) call deallocate (comp) >>> else if (finalizer or subcomponents have a finalizer) call >>> FINAL_WRAPPER >> >> Well, the question is whether one wants to call a finalize wrapper >> for a simple "comp%alloctable_int(10)" or not. In the current scheme, >> I tried to avoid calling a finalizer wrapper for simple allocatable >> components. >> >> Thus, one has the choice: a) Directly call DEALLOCATE for alloctable >> components of subcomponents b) Always call the finalizer wrapper >> also for nonalloctable TYPEs (with finalizable/allocatable >> components) >> >> (a) is more direct and possibly a bit faster while (b) makes the >> wrapper function a tad smaller. >OK, this is a deliberate choice of implementation to avoid call >overhead. I slightly prefer (b), but we can keep (a). >I'm fine with (a) if the code walking the components is shared - which >avoids c vs. comp issues by the way ;-) . > >> * * * >> >> Regarding the flag or nonflag final_comp, I have to admit that I >> still do not completely understand how you would implement it. >> >> One option would be something like the following >> >> bool has_final_comp(derived) { for (comp = derived->components; comp; >> comp = comp->next) { if (comp->attr.pointer) continue; if >> (comp->f2k_derived->finalizers || comp->ts.type == BT_CLASS) return >> true; if (comp->ts.type == BT_DERIVED && >> has_final_comp(comp->ts.u.derived)) return true; } return false } >This was my initial proposition. The benefit is it is very clear how it >works compared to manual setting the flag here and there. >As you raised a performance issue, I proposed something like this: > >bool has_final_comp(derived) { > bool retval = false; > > if (derived->cache.final_comp_set) >return derived->cache.final_comp; > > for (comp = derived->components; comp; comp = comp->next) > { > if (comp->attr.pointer) > continue; >if (comp->f2k_derived->finalizers || comp->ts.type == BT_CLASS) > { >retval = true; >break; > } >if (comp->ts.type == BT_DERIVED >&& has_final_comp(comp->ts.u.derived)) > { >retval = true; >break; > } > } > derived->cache.final_comp_set = 1; > derived->cache.final_comp = retval; > return retval; >} > >It's no big deal anyway. >I dream of a compiler where all the non-standard symbol attribute flags, >expression rank and typespec, etc, would be implemented like this... No >need for resolution, etc; it would just work everywhere. >I know the story, patches welcome; they may come, one day... > >Mikael >
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
On 25/08/2012 22:06, Tobias Burnus wrote: If comp has finalizable subcomponents, it has a finalization wrapper, which is (or should be) caught above, so this branch is (or should be) unreachable. >>> I probably miss something, but I don't see why this branch should >>> be unreachable. One has: >>> >>> if (component is allocatable) call DEALLOCATE(comp) ! which might >>> invoke finalizers else if (component itself has a finalizer) call >>> FINAL_WRAPPER else for all nonpointer subcomponents which are >>> allocatables, have finalizers or have allocatable/finalizable >>> components, call finalize_component. end if >> I expected something like: if (allocatable) call deallocate (comp) >> else if (finalizer or subcomponents have a finalizer) call >> FINAL_WRAPPER > > Well, the question is whether one wants to call a finalize wrapper > for a simple "comp%alloctable_int(10)" or not. In the current scheme, > I tried to avoid calling a finalizer wrapper for simple allocatable > components. > > Thus, one has the choice: a) Directly call DEALLOCATE for alloctable > components of subcomponents b) Always call the finalizer wrapper – > also for nonalloctable TYPEs (with finalizable/allocatable > components) > > (a) is more direct and possibly a bit faster while (b) makes the > wrapper function a tad smaller. OK, this is a deliberate choice of implementation to avoid call overhead. I slightly prefer (b), but we can keep (a). I'm fine with (a) if the code walking the components is shared - which avoids c vs. comp issues by the way ;-) . > * * * > > Regarding the flag or nonflag final_comp, I have to admit that I > still do not completely understand how you would implement it. > > One option would be something like the following > > bool has_final_comp(derived) { for (comp = derived->components; comp; > comp = comp->next) { if (comp->attr.pointer) continue; if > (comp->f2k_derived->finalizers || comp->ts.type == BT_CLASS) return > true; if (comp->ts.type == BT_DERIVED && > has_final_comp(comp->ts.u.derived)) return true; } return false } This was my initial proposition. The benefit is it is very clear how it works compared to manual setting the flag here and there. As you raised a performance issue, I proposed something like this: bool has_final_comp(derived) { bool retval = false; if (derived->cache.final_comp_set) return derived->cache.final_comp; for (comp = derived->components; comp; comp = comp->next) { if (comp->attr.pointer) continue; if (comp->f2k_derived->finalizers || comp->ts.type == BT_CLASS) { retval = true; break; } if (comp->ts.type == BT_DERIVED && has_final_comp(comp->ts.u.derived)) { retval = true; break; } } derived->cache.final_comp_set = 1; derived->cache.final_comp = retval; return retval; } It's no big deal anyway. I dream of a compiler where all the non-standard symbol attribute flags, expression rank and typespec, etc, would be implemented like this... No need for resolution, etc; it would just work everywhere. I know the story, patches welcome; they may come, one day... Mikael
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Mikael Morin wrote: What if only comp's subcomponents are finalizable, the finalization wrapper should still be called, shouldn't it? Well, that's handled in the "else" branch. There, I walk all subcomponents. I do not need to walk them in case there is a finalizer as the called finalization wrapper will handle them. Actually, I don't understand why you walk twice over the subcomponents: in the else branch here and in the finalizer. Well, I only walk once per component. However, I could unconditionally call this function – and move some of the checks from the main program here. If comp has finalizable subcomponents, it has a finalization wrapper, which is (or should be) caught above, so this branch is (or should be) unreachable. I probably miss something, but I don't see why this branch should be unreachable. One has: if (component is allocatable) call DEALLOCATE(comp) ! which might invoke finalizers else if (component itself has a finalizer) call FINAL_WRAPPER else for all nonpointer subcomponents which are allocatables, have finalizers or have allocatable/finalizable components, call finalize_component. end if I expected something like: if (allocatable) call deallocate (comp) else if (finalizer or subcomponents have a finalizer) call FINAL_WRAPPER Well, the question is whether one wants to call a finalize wrapper for a simple "comp%alloctable_int(10)" or not. In the current scheme, I tried to avoid calling a finalizer wrapper for simple allocatable components. Thus, one has the choice: a) Directly call DEALLOCATE for alloctable components of subcomponents b) Always call the finalizer wrapper – also for nonalloctable TYPEs (with finalizable/allocatable components) (a) is more direct and possibly a bit faster while (b) makes the wrapper function a tad smaller. As said above, I don't understand why you would walk over the components twice I don't. I touch every ((sub)sub)component only once; I only do a deep walk until there is either no component or a pointer or an allocatable or a finalizable component. I do acknowledge that I repeat some of the logic by handling the outer component in the wrapper and the inner (sub)subcomponents in the final_components. + else if (comp->ts.type == BT_CLASS && CLASS_DATA (comp) + && CLASS_DATA (comp)->attr.allocatable) +alloc_comp = true; Shouldn't one assume without condition that there are allocatable or finalizable subcomponents when there is a polymorphic component? Well, we do not deallocate/finalize polymorphic POINTER components. Indeed, then I prefer having !CLASS_DATA(comp)->attr.pointer. Okay, that's equivalent; though, I have to admit that I prefer the current version, which I regard as cleaner. * * * Regarding the flag or nonflag final_comp, I have to admit that I still do not completely understand how you would implement it. One option would be something like the following bool has_final_comp(derived) { for (comp = derived->components; comp; comp = comp->next) { if (comp->attr.pointer) continue; if (comp->f2k_derived->finalizers || comp->ts.type == BT_CLASS) return true; if (comp->ts.type == BT_DERIVED && has_final_comp(comp->ts.u.derived)) return true; } return false } in class.c Another is the version which gets set in parse.c. However, I do not understand what you mean by: If performance is a problem, the function could use the flag as a backend. As long as the field is used and set in a single place, I don't mind. I don't have a strong opinion either, there is already a full bag of flags; one more wouldn't make things dramatically worse. Tobias
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
On 25/08/2012 17:21, Tobias Burnus wrote: > (And nonallocatble, nonpointer > components do not exist.) I missed that indeed. >> What if only comp's subcomponents are finalizable, the finalization >> wrapper should still be called, shouldn't it? > > Well, that's handled in the "else" branch. There, I walk all > subcomponents. I do not need to walk them in case there is a finalizer > as the called finalization wrapper will handle them. Actually, I don't understand why you walk twice over the subcomponents: in the else branch here and in the finalizer. >> If comp has finalizable subcomponents, it has a finalization wrapper, >> which is (or should be) caught above, so this branch is (or should be) >> unreachable. > > I probably miss something, but I don't see why this branch should be > unreachable. One has: > > if (component is allocatable) > call DEALLOCATE(comp) ! which might invoke finalizers > else if (component itself has a finalizer) > call FINAL_WRAPPER > else >for all nonpointer subcomponents which are allocatables, have > finalizers or have allocatable/finalizable components, call > finalize_component. > end if I expected something like: if (allocatable) call deallocate (comp) else if (finalizer or subcomponents have a finalizer) call FINAL_WRAPPER As said above, I don't understand why you would walk over the components twice >>> >+ else if (comp->ts.type == BT_CLASS && CLASS_DATA (comp) >>> >+ && CLASS_DATA (comp)->attr.allocatable) >>> >+alloc_comp = true; >> Shouldn't one assume without condition that there are allocatable or >> finalizable subcomponents when there is a polymorphic component? > > Well, we do not deallocate/finalize polymorphic POINTER components. Indeed, then I prefer having !CLASS_DATA(comp)->attr.pointer. >>> >diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c >>> >index 44b1900..4cafefe 100644 >>> >--- a/gcc/fortran/parse.c >>> >+++ b/gcc/fortran/parse.c >>> >@@ -2250,6 +2250,16 @@ endType: >>> >sym->attr.lock_comp = 1; >>> > } >>> > >+ /* Look for finalizers. */ >>> >+ if (c->attr.final_comp >> c->attr.final_comp is never set. >> >> I would like to avoid if possible yet another symbol attribute set in >> three different functions in three different files and used all over the >> place. What about using a function "calculating" the predicate this >> time? > > Maybe, however, one has then to call the function a lot of times: In > generate_finalization_wrapper for the whole type, then for the new added > components, and then for each component in finalize_component. With the > current code, the latter has a complexity of approx. O(n lg n), but one > might be able to improve it a bit by restructuring the code. (On the > other hand, "n" is probably not excessively large.) > If performance is a problem, the function could use the flag as a backend. As long as the field is used and set in a single place, I don't mind. I don't have a strong opinion either, there is already a full bag of flags; one more wouldn't make things dramatically worse. Mikael
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Dear Mikael, dear all, Mikael Morin wrote: the patch mixes deallocation and finalization, which are treated separately in the standard. First, I want to remark that the standard - in many cases - does not require memory freeing ("deallocation"), it "merely" makes it possible that one does not leak memory with allocatables. The actually freeing of the memory is just a matter of the qualify of the implementation. Secondly, for a polymorphic type, one does not know at compile time whether it has allocatable components or not - nor whether it has a finalizer or not. Hence, I do not see another possibility to have a common _free/_final entry point in the vtable. As there has to be a common entry point, I think it makes sense to have a single finalization wrapper which handles both. (I had also initially thought, that one could handle those two cases separately, but now I don't see it anymore.) 1. some weird cases are not correctly covered (polymorphic components, multiple level of finalizable and/or non-finalizable components, of inheritance, ...) I do believe that polymorphic components are correctly handled: If they are a POINTER, they are untouched but if they are ALLOCATABLE, one calls DEALLOCATE for the component, which should handle the finalization/deallocation correctly. (And nonallocatble, nonpointer components do not exist.) I would like to point out that forcing the wrapper's array argument to be contiguous will lead to poor code as repacking will be needed with inherited types to call the parent's wrapper (and the parent's parent's, etc...). I think that's unavoidable with the current array descriptor, which assumes that the stride is always a multiple of the size of the type. I concur that with the new array descriptor, one restrict the copy-in/copy-out to calling explict-shape/assumed-size finalizers, which probably do not occur in practice. >+finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp, >+ e = gfc_copy_expr (expr); >+ e->ref = gfc_get_ref (); You should walk to the end of the reference chain. Otherwise you are overwriting it here. I will do this. >+ if (comp->attr.allocatable >+ || (comp->ts.type == BT_CLASS && CLASS_DATA (comp) >+ && CLASS_DATA (comp)->attr.allocatable)) >+{ >+} >+ else if (comp->ts.type == BT_DERIVED >+ && comp->ts.u.derived->f2k_derived >+ && comp->ts.u.derived->f2k_derived->finalizers) What about polymorphic components? I have to admit that the code is a bit implicit: polymorphic components are either ALLOCATABLE - and hence handled in the "if" block, or they are pointers - in which case this function is not called at all. What if only comp's subcomponents are finalizable, the finalization wrapper should still be called, shouldn't it? Well, that's handled in the "else" branch. There, I walk all subcomponents. I do not need to walk them in case there is a finalizer as the called finalization wrapper will handle them. >+ else >+{ >+ gfc_component *c; >+ >+ gcc_assert ((comp->attr.alloc_comp || comp->attr.final_comp) >+ && comp->ts.type != BT_CLASS); >+ for (c = comp->ts.u.derived->components; c; c = c->next) >+ if ((comp->ts.type != BT_CLASS && !comp->attr.pointer >+&& (comp->attr.alloc_comp || comp->attr.allocatable >+|| comp->attr.final_comp)) >+ || ((comp->ts.type == BT_CLASS && CLASS_DATA (comp) >+&& CLASS_DATA (comp)->attr.allocatable))) >+ finalize_component (e, comp->ts.u.derived, comp, stat, code); >+} This doesn't work, you use comp instead of c. I hate copy-and-paste bugs. Thanks. If there is a polymorphic component whose declared type is not finalizable, but whose actual type is, the finalization wrapper should still be called. But it will, as written above, polymorphic components are allocatable (or they are pointers and won't get finalized). If comp has finalizable subcomponents, it has a finalization wrapper, which is (or should be) caught above, so this branch is (or should be) unreachable. I probably miss something, but I don't see why this branch should be unreachable. One has: if (component is allocatable) call DEALLOCATE(comp) ! which might invoke finalizers else if (component itself has a finalizer) call FINAL_WRAPPER else for all nonpointer subcomponents which are allocatables, have finalizers or have allocatable/finalizable components, call finalize_component. end if >+ block->symtree = gfc_find_symtree (sub_ns->sym_root, "c_f_pointer"); This is useless... I concur. >+ bool alloc_comp = false; This is misnamed, it should be final_comp or something. I concur, its use became extended during the development of the patch. >+ for (comp = vtab->ts.u.derived->components; comp; comp = comp->next) >+ if (comp->name[0] == '_' && comp->name[1] == 'f') I have no strong opinion about it, but slightly prefer strcmp (
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
On 19/08/2012 19:50, Tobias Burnus wrote: > Dear all, > > attached is a slightly updated patch: > > * Call finalizers of nonallocatable, nonpointer components > * Generate FINAL wrapper for abstract types which have a finalizer. (The > allocatable components are deallocated in the first type (abstract or > not) which has a finalizer, i.e. abstract + finalizer or first > nonabstract type.) > > I had to disable some resolve warning; I did so by introducing an > attr.artificial. I used it to also fix PR 51632, where we errored out > for __def_init and __copy where there were coarray components. > > Build and regtested on x86-64-linux. > OK for the trunk? > > Tobias Hello, some general comment: the patch mixes deallocation and finalization, which are treated separately in the standard. I don' know at this point whether it will make our life really tougher or not, but I think it makes the code slightly more difficult to read. I have a mixed general feeling about the patch that 1. some weird cases are not correctly covered (polymorphic components, multiple level of finalizable and/or non-finalizable components, of inheritance, ...) 2. some of the above "incorrectnesses" may actually cancel each other; the patch is implemented differently than how I thought it would be. I may be missing the point after all. I would like to point out that forcing the wrapper's array argument to be contiguous will lead to poor code as repacking will be needed with inherited types to call the parent's wrapper (and the parent's parent's, etc...). More specific comments below. Mikael > 2012-08-19 Alessandro Fanfarillo > Tobias Burnus > > PR fortran/37336 > * gfortran.h (symbol_attribute): Add artifical and final_comp. > * parse.c (parse_derived): Set final_comp. > * module.c (mio_symbol_attribute): Handle final.comp. > * class.c (gfc_build_class_symbol): Defer creation of the vtab > if the DT has finalizers, mark generated symbols as > attr.artificial. > (finalize_component, finalization_scalarizer, > generate_finalization_wrapper): New static functions. > (gfc_find_derived_vtab): Add _final component and call > generate_finalization_wrapper. > * dump-parse-tree.c (show_f2k_derived): Use resolved > proc_tree->n.sym rather than unresolved proc_sym. > * resolve.c (gfc_resolve_finalizers): Remove not-implemented > error and ensure that the vtab exists. > (resolve_fl_derived): Resolve finalizers before > generating the vtab. > (resolve_symbol): Also allow assumed-rank arrays with CONTIGUOUS; > skip artificial symbols. > (resolve_fl_derived0): Skip artificial symbols. > > 2012-08-19 Alessandro Fanfarillo > Tobias Burnus > > PR fortran/51632 > * gfortran.dg/coarray_class_1.f90: New. > > PR fortran/37336 > * gfortran.dg/coarray_poly_3.f90: Update dg-error. > * gfortran.dg/auto_dealloc_2.f90: Update scan-tree-dump-times. > * gfortran.dg/class_19.f03: Ditto. > * gfortran.dg/finalize_4.f03: Remove dg-excess-errors > for not implemented. > * gfortran.dg/finalize_5.f03: Ditto. > * gfortran.dg/finalize_7.f03: Ditto. > > diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c > index 21a91ba..122cc43 100644 > --- a/gcc/fortran/class.c > +++ b/gcc/fortran/class.c > @@ -689,6 +694,672 @@ copy_vtab_proc_comps (gfc_symbol *declared, gfc_symbol > *vtype) > } > > > +/* Call DEALLOCATE for the passed component if it is allocatable, if it is > + neither allocatable nor a pointer but has a finalizer, call it. If it > + is a nonpointer component with allocatable or finalizes components, walk > + them. Either of the is required; other nonallocatables and pointers aren't > + handled gracefully. > + Note: The DEALLOCATE handling takes care of finalizers, coarray > + deregistering and allocatable components of the allocatable. */ > + > +void > +finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp, > + gfc_expr *stat, gfc_code **code) > +{ > + gfc_expr *e; > + e = gfc_copy_expr (expr); > + e->ref = gfc_get_ref (); You should walk to the end of the reference chain. Otherwise you are overwriting it here. Unless you avoid recursing, in which case you can assert it was NULL. > + e->ref->type = REF_COMPONENT; > + e->ref->u.c.sym = derived; > + e->ref->u.c.component = comp; > + e->ts = comp->ts; > + > + if (comp->attr.dimension > + || (comp->ts.type == BT_CLASS && CLASS_DATA (comp) > + && CLASS_DATA (comp)->attr.dimension)) > +{ > + e->ref->next = gfc_get_ref (); > + e->ref->next->type = REF_ARRAY; > + e->ref->next->u.ar.type = AR_FULL; > + e->ref->next->u.ar.dimen = 0; > + e->ref->next->u.ar.as = comp->ts.type == BT_CLASS ? CLASS_DATA > (comp)->as > + : comp->as; > + e-
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Dear Alessandro, Alessandro Fanfarillo wrote: there are some problems with the final-wrapper-v2.diff patch; I get Internal Error at (1): gfc_code2string(): Bad code for every test case that I use; in attachment final2.f90. Fixed by the patch below. However, note that the current patch only implement the wrapper function - it doesn't handle calling the wrapper function. That's requires a follow up patch. (That was the reason that I did not do extensive test.) The patch is a complete module.c patch, not incrementally based on the previous patch. Tobias diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c index a4ff199..3e636cd 100644 --- a/gcc/fortran/module.c +++ b/gcc/fortran/module.c @@ -1840,17 +1840,18 @@ typedef enum AB_ELEMENTAL, AB_PURE, AB_RECURSIVE, AB_GENERIC, AB_ALWAYS_EXPLICIT, AB_CRAY_POINTER, AB_CRAY_POINTEE, AB_THREADPRIVATE, AB_ALLOC_COMP, AB_POINTER_COMP, AB_PROC_POINTER_COMP, AB_PRIVATE_COMP, - AB_VALUE, AB_VOLATILE, AB_PROTECTED, AB_LOCK_COMP, + AB_VALUE, AB_VOLATILE, AB_PROTECTED, AB_LOCK_COMP, AB_FINAL_COMP, AB_IS_BIND_C, AB_IS_C_INTEROP, AB_IS_ISO_C, AB_ABSTRACT, AB_ZERO_COMP, AB_IS_CLASS, AB_PROCEDURE, AB_PROC_POINTER, AB_ASYNCHRONOUS, AB_CODIMENSION, AB_COARRAY_COMP, AB_VTYPE, AB_VTAB, AB_CONTIGUOUS, AB_CLASS_POINTER, - AB_IMPLICIT_PURE + AB_IMPLICIT_PURE, AB_ARTIFICIAL } ab_attribute; static const mstring attr_bits[] = { minit ("ALLOCATABLE", AB_ALLOCATABLE), +minit ("ARTIFICIAL", AB_ARTIFICIAL), minit ("ASYNCHRONOUS", AB_ASYNCHRONOUS), minit ("DIMENSION", AB_DIMENSION), minit ("CODIMENSION", AB_CODIMENSION), @@ -1883,6 +1884,7 @@ static const mstring attr_bits[] = minit ("VALUE", AB_VALUE), minit ("ALLOC_COMP", AB_ALLOC_COMP), minit ("COARRAY_COMP", AB_COARRAY_COMP), +minit ("FINAL_COMP", AB_FINAL_COMP), minit ("LOCK_COMP", AB_LOCK_COMP), minit ("POINTER_COMP", AB_POINTER_COMP), minit ("PROC_POINTER_COMP", AB_PROC_POINTER_COMP), @@ -1975,6 +1977,8 @@ mio_symbol_attribute (symbol_attribute *attr) { if (attr->allocatable) MIO_NAME (ab_attribute) (AB_ALLOCATABLE, attr_bits); + if (attr->artificial) + MIO_NAME (ab_attribute) (AB_ARTIFICIAL, attr_bits); if (attr->asynchronous) MIO_NAME (ab_attribute) (AB_ASYNCHRONOUS, attr_bits); if (attr->dimension) @@ -2057,6 +2061,8 @@ mio_symbol_attribute (symbol_attribute *attr) MIO_NAME (ab_attribute) (AB_PRIVATE_COMP, attr_bits); if (attr->coarray_comp) MIO_NAME (ab_attribute) (AB_COARRAY_COMP, attr_bits); + if (attr->final_comp) + MIO_NAME (ab_attribute) (AB_FINAL_COMP, attr_bits); if (attr->lock_comp) MIO_NAME (ab_attribute) (AB_LOCK_COMP, attr_bits); if (attr->zero_comp) @@ -2090,6 +2096,9 @@ mio_symbol_attribute (symbol_attribute *attr) case AB_ALLOCATABLE: attr->allocatable = 1; break; + case AB_ARTIFICIAL: + attr->artificial = 1; + break; case AB_ASYNCHRONOUS: attr->asynchronous = 1; break; @@ -2198,6 +2207,9 @@ mio_symbol_attribute (symbol_attribute *attr) case AB_COARRAY_COMP: attr->coarray_comp = 1; break; + case AB_FINAL_COMP: + attr->final_comp = 1; + break; case AB_LOCK_COMP: attr->lock_comp = 1; break;
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Dear Tobias, there are some problems with the final-wrapper-v2.diff patch; I get the following error final2.f90:71.15: end module test 1 Internal Error at (1): gfc_code2string(): Bad code for every test case that I use; in attachment final2.f90. Regards Alessandro 2012/8/19 Tobias Burnus : > Dear all, > > attached is a slightly updated patch: > > * Call finalizers of nonallocatable, nonpointer components > * Generate FINAL wrapper for abstract types which have a finalizer. (The > allocatable components are deallocated in the first type (abstract or not) > which has a finalizer, i.e. abstract + finalizer or first nonabstract type.) > > I had to disable some resolve warning; I did so by introducing an > attr.artificial. I used it to also fix PR 51632, where we errored out for > __def_init and __copy where there were coarray components. > > Build and regtested on x86-64-linux. > OK for the trunk? > > Tobias -- final2.f90 Description: Binary data
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
* PING * On August 19, 2012, Tobias Burnus wrote: Dear all, attached is a slightly updated patch: * Call finalizers of nonallocatable, nonpointer components * Generate FINAL wrapper for abstract types which have a finalizer. (The allocatable components are deallocated in the first type (abstract or not) which has a finalizer, i.e. abstract + finalizer or first nonabstract type.) I had to disable some resolve warning; I did so by introducing an attr.artificial. I used it to also fix PR 51632, where we errored out for __def_init and __copy where there were coarray components. Build and regtested on x86-64-linux. OK for the trunk? Tobias
Re: [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Dear all, attached is a slightly updated patch: * Call finalizers of nonallocatable, nonpointer components * Generate FINAL wrapper for abstract types which have a finalizer. (The allocatable components are deallocated in the first type (abstract or not) which has a finalizer, i.e. abstract + finalizer or first nonabstract type.) I had to disable some resolve warning; I did so by introducing an attr.artificial. I used it to also fix PR 51632, where we errored out for __def_init and __copy where there were coarray components. Build and regtested on x86-64-linux. OK for the trunk? Tobias 2012-08-19 Alessandro Fanfarillo Tobias Burnus PR fortran/37336 * gfortran.h (symbol_attribute): Add artifical and final_comp. * parse.c (parse_derived): Set final_comp. * module.c (mio_symbol_attribute): Handle final.comp. * class.c (gfc_build_class_symbol): Defer creation of the vtab if the DT has finalizers, mark generated symbols as attr.artificial. (finalize_component, finalization_scalarizer, generate_finalization_wrapper): New static functions. (gfc_find_derived_vtab): Add _final component and call generate_finalization_wrapper. * dump-parse-tree.c (show_f2k_derived): Use resolved proc_tree->n.sym rather than unresolved proc_sym. * resolve.c (gfc_resolve_finalizers): Remove not-implemented error and ensure that the vtab exists. (resolve_fl_derived): Resolve finalizers before generating the vtab. (resolve_symbol): Also allow assumed-rank arrays with CONTIGUOUS; skip artificial symbols. (resolve_fl_derived0): Skip artificial symbols. 2012-08-19 Alessandro Fanfarillo Tobias Burnus PR fortran/51632 * gfortran.dg/coarray_class_1.f90: New. PR fortran/37336 * gfortran.dg/coarray_poly_3.f90: Update dg-error. * gfortran.dg/auto_dealloc_2.f90: Update scan-tree-dump-times. * gfortran.dg/class_19.f03: Ditto. * gfortran.dg/finalize_4.f03: Remove dg-excess-errors for not implemented. * gfortran.dg/finalize_5.f03: Ditto. * gfortran.dg/finalize_7.f03: Ditto. diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c index 21a91ba..122cc43 100644 --- a/gcc/fortran/class.c +++ b/gcc/fortran/class.c @@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see declared type of the class variable and its attributes (pointer/allocatable/dimension/...). * _vptr: A pointer to the vtable entry (see below) of the dynamic type. - + For each derived type we set up a "vtable" entry, i.e. a structure with the following fields: * _hash: A hash value serving as a unique identifier for this type. @@ -42,6 +42,9 @@ along with GCC; see the file COPYING3. If not see * _extends: A pointer to the vtable entry of the parent derived type. * _def_init: A pointer to a default initialized variable of this type. * _copy: A procedure pointer to a copying procedure. +* _final:A procedure pointer to a wrapper function, which frees + allocatable components and calls FINAL subroutines. + After these follow procedure pointer components for the specific type-bound procedures. */ @@ -572,7 +575,9 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr, if (gfc_add_component (fclass, "_vptr", &c) == FAILURE) return FAILURE; c->ts.type = BT_DERIVED; - if (delayed_vtab) + if (delayed_vtab + || (ts->u.derived->f2k_derived + && ts->u.derived->f2k_derived->finalizers)) c->ts.u.derived = NULL; else { @@ -689,6 +694,672 @@ copy_vtab_proc_comps (gfc_symbol *declared, gfc_symbol *vtype) } +/* Call DEALLOCATE for the passed component if it is allocatable, if it is + neither allocatable nor a pointer but has a finalizer, call it. If it + is a nonpointer component with allocatable or finalizes components, walk + them. Either of the is required; other nonallocatables and pointers aren't + handled gracefully. + Note: The DEALLOCATE handling takes care of finalizers, coarray + deregistering and allocatable components of the allocatable. */ + +void +finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp, + gfc_expr *stat, gfc_code **code) +{ + gfc_expr *e; + e = gfc_copy_expr (expr); + e->ref = gfc_get_ref (); + e->ref->type = REF_COMPONENT; + e->ref->u.c.sym = derived; + e->ref->u.c.component = comp; + e->ts = comp->ts; + + if (comp->attr.dimension + || (comp->ts.type == BT_CLASS && CLASS_DATA (comp) + && CLASS_DATA (comp)->attr.dimension)) +{ + e->ref->next = gfc_get_ref (); + e->ref->next->type = REF_ARRAY; + e->ref->next->u.ar.type = AR_FULL; + e->ref->next->u.ar.dimen = 0; + e->ref->next->u.ar.as = comp->ts.type == BT_CLASS ? CLASS_DATA (comp)->as + : comp->as; + e->rank = e->ref->next->u.ar.as->rank; +} + + if (comp->attr.allocatable + || (comp->ts.type == BT_CLASS && CLASS_DATA (comp) + && CLASS_DATA (comp)->attr.allocatable))
Re: [EXTERNAL] [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Hi Damian, dear all, Rouson, Damian wrote: Thanks for your work on this. This is a big step. I would add to your list the following: (4) If the entity is of extended type and the parent type has a component that is finalizable, the parent component's component is finalized. I believe that's already covered by (3) which invokes (1) for the parent type – and handles the parent's components via (2). (Besides, in the standard is not much more than (1)–(3); thus, if it weren't implied by those, it likely wouldn't be part of the standard at all.) In ForTrilnos, we need for this to happen even when the parent is abstract but has a finalizable component. I think that's (mostly) handled via the current wrapper subroutine (i.e. the finalizer of an allocatable component, which has been added in an abstract type, is finalized). However, I think there are two issues with the current patch: (a) If an abstract type has itself finalizer, it is currently not called. (Only its components are finalized) (b) The current patch doesn't finalize nonallocatable [nonpointer] components, but those might also have a finalizer. Thanks for your comments. Tobias On 8/13/12 1:05 PM, "Tobias Burnus" wrote: The finalization is done as follows (F2008, "4.5.6.2 The finalization process") "(1) If the dynamic type of the entity has a final subroutine whose dummy argument has the same kind type parameters and rank as the entity being finalized, it is called with the entity as an actual argument. Otherwise, if there is an elemental final subroutine whose dummy argument has the same kind type parameters as the entity being finalized, it is called with the entity as an actual argument. Otherwise, no subroutine is called at this point. "(2) All finalizable components that appear in the type definition are finalized in a processor-dependent order. If the entity being finalized is an array, each finalizable component of each element of that entity is finalized separately. "(3) If the entity is of extended type and the parent type is finalizable, the parent component is finalized."
Re: [EXTERNAL] [Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Hi Tobias, Thanks for your work on this. This is a big step. I would add to your list the following: (4) If the entity is of extended type and the parent type has a component that is finalizable, the parent component's component is finalized. In ForTrilnos, we need for this to happen even when the parent is abstract but has a finalizable component. So far, the IBM, NAG, and Cray compilers support this use case and we've had enough dialogue with committee members that I'm confident it's required by the standard, although I can't cite the specific part of the standard that requires it. Please copy my staff member Karla Morris on any replies. Thanks again! Damian On 8/13/12 1:05 PM, "Tobias Burnus" wrote: >Dear all, > >Attached is the first part of a patch which will implement finalization >support and polymorphic freeing in gfortran. > > >It addresses two needs: > >a) For polymorphic ("CLASS") variables, allocatable components have to >be freed; however, at compile time only the allocatable components of >the declared type are known and the dynamic type might have more > >b) Fortran 2003 allows finalization subroutines ("FINAL", destructors), >which can be elemental, scalar or for a given rank (any array type is >allowed). Those should be called for DEALLOCATE, leaving the scope >(unless saved), intrinsic assignment and with intent(out). > > >The finalization is done as follows (F2008, "4.5.6.2 The finalization >process") > >"(1) If the dynamic type of the entity has a final subroutine whose >dummy argument has the same kind type parameters and rank as the entity >being finalized, it is called with the entity as an actual argument. >Otherwise, if there is an elemental final subroutine whose dummy >argument has the same kind type parameters as the entity being >finalized, it is called with the entity as an actual argument. >Otherwise, no subroutine is called at this point. > >"(2) All finalizable components that appear in the type definition are >finalized in a processor-dependent order. If the entity being finalized >is an array, each finalizable component of each element of that entity >is finalized separately. > >"(3) If the entity is of extended type and the parent type is >finalizable, the parent component is finalized." > > >The idea is to create a wrapper function which handles those steps - and >attach a reference to the dynamic type (i.e. add it via proc-pointer to >the vtable). Additionally, the wrapper can be directly called for TYPE. > > >The attached patch implements the generation of the wrapper subroutine; >it does not yet implement the actual calls. The wrapper is generated on >Fortran AST level and creates code similar to > >subroutine final_wrapper_for_type_t (array) >type(t), intent(inout) :: array(..) >integer, pointer :: ptr >integer(c_intptr_t) :: i, addr > >select case (rank (array)) >case (3) >call final_rank3 (array) >case default: >do i = 0, size (array)-1 >addr = transfer (c_loc (array), addr) + i * STORAGE_SIZE (array) >call c_f_pointer (transfer (addr, c_ptr), ptr) >call elemental_final (ptr) >end do >end select > >! For all noninherited allocatable components, call >! DEALLOCATE(array(:)%comp, stat=ignore) >! scalarized as above > >call final_wrapper_of_parent (array(...)%parent) >end subroutine final_wrapper_for_type_t > > >Note 1: The call to the parent type requires packing support for >assumed-rank arrays, which has not yet been implemented (also required >for TS29113, though not for this usage). That is, without further >patches, the wrapper will only work for scalars or if the parent has no >wrapper subroutine. > >Note 2: The next step will be to add the calls to the wrapper, starting >with an explicit DEALLOCATE. > > >I intent to commit the patch, when approved, without allowing FINAL at >resolution time; that way there is no false impression that finalization >actually works. > >Build and regtested on x86-64-gnu-linux. >OK for the trunk? > >* * * > >Note: The patch will break gfortran's OOP ABI. It does so by adding >"_final" to the virtual table (vtab). > >I think breaking the ABI for this functionality is unavoidable. The ABI >change only affects code which uses the CLASS (polymorphic variables) >and the issue only raises if one mixes old with new code for the same >derived type. However, if one does so (e.g. by incomplete >recompilation), segfaults and similar issues will occur. Hence, I am >considering to bump the .mod version; that will effectively force a >recompilation and thus avoid the issue. The down side is that it will >also break packages (e.g. of Linux distributions) which ship .mod files >(sorry!). What do you think? > >I think it could then be combined with Janus' proc-pointer patch, which >changes the assembler name of (non-Bind(C)) procedure pointers, declared >at module level. Again, by forcing recompilation, the .mod version bump >should ensure that users don't see the ABI breakage. His patch is at >http://gcc.gnu.org/ml/fortran/2012-04/
[Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Dear all, Attached is the first part of a patch which will implement finalization support and polymorphic freeing in gfortran. It addresses two needs: a) For polymorphic ("CLASS") variables, allocatable components have to be freed; however, at compile time only the allocatable components of the declared type are known – and the dynamic type might have more b) Fortran 2003 allows finalization subroutines ("FINAL", destructors), which can be elemental, scalar or for a given rank (any array type is allowed). Those should be called for DEALLOCATE, leaving the scope (unless saved), intrinsic assignment and with intent(out). The finalization is done as follows (F2008, "4.5.6.2 The finalization process") "(1) If the dynamic type of the entity has a final subroutine whose dummy argument has the same kind type parameters and rank as the entity being finalized, it is called with the entity as an actual argument. Otherwise, if there is an elemental final subroutine whose dummy argument has the same kind type parameters as the entity being finalized, it is called with the entity as an actual argument. Otherwise, no subroutine is called at this point. "(2) All finalizable components that appear in the type definition are finalized in a processor-dependent order. If the entity being finalized is an array, each finalizable component of each element of that entity is finalized separately. "(3) If the entity is of extended type and the parent type is finalizable, the parent component is finalized." The idea is to create a wrapper function which handles those steps - and attach a reference to the dynamic type (i.e. add it via proc-pointer to the vtable). Additionally, the wrapper can be directly called for TYPE. The attached patch implements the generation of the wrapper subroutine; it does not yet implement the actual calls. The wrapper is generated on Fortran AST level and creates code similar to subroutine final_wrapper_for_type_t (array) type(t), intent(inout) :: array(..) integer, pointer :: ptr integer(c_intptr_t) :: i, addr select case (rank (array)) case (3) call final_rank3 (array) case default: do i = 0, size (array)-1 addr = transfer (c_loc (array), addr) + i * STORAGE_SIZE (array) call c_f_pointer (transfer (addr, c_ptr), ptr) call elemental_final (ptr) end do end select ! For all noninherited allocatable components, call ! DEALLOCATE(array(:)%comp, stat=ignore) ! scalarized as above call final_wrapper_of_parent (array(...)%parent) end subroutine final_wrapper_for_type_t Note 1: The call to the parent type requires packing support for assumed-rank arrays, which has not yet been implemented (also required for TS29113, though not for this usage). That is, without further patches, the wrapper will only work for scalars or if the parent has no wrapper subroutine. Note 2: The next step will be to add the calls to the wrapper, starting with an explicit DEALLOCATE. I intent to commit the patch, when approved, without allowing FINAL at resolution time; that way there is no false impression that finalization actually works. Build and regtested on x86-64-gnu-linux. OK for the trunk? * * * Note: The patch will break gfortran's OOP ABI. It does so by adding "_final" to the virtual table (vtab). I think breaking the ABI for this functionality is unavoidable. The ABI change only affects code which uses the CLASS (polymorphic variables) and the issue only raises if one mixes old with new code for the same derived type. However, if one does so (e.g. by incomplete recompilation), segfaults and similar issues will occur. Hence, I am considering to bump the .mod version; that will effectively force a recompilation and thus avoid the issue. The down side is that it will also break packages (e.g. of Linux distributions) which ship .mod files (sorry!). What do you think? I think it could then be combined with Janus' proc-pointer patch, which changes the assembler name of (non-Bind(C)) procedure pointers, declared at module level. Again, by forcing recompilation, the .mod version bump should ensure that users don't see the ABI breakage. His patch is at http://gcc.gnu.org/ml/fortran/2012-04/msg00033.html (I think is okay, but I believe it has not yet been reviewed.) Tobias PS: I used the following test case to test whether the wrapper generation and scalarization works; it properly prints 11,22,33,44,55,66 and also the dump looks okay for various versions. The scalarization code should work relatively well; there is only one call to an external function: For SIZE gfortran - for what ever reason - doesn't generate inline code, but calls libgfortran. But now the test code: module m type tt end type tt type t ! type(tt), allocatable :: comp1 integer :: val contains final bar1 end type t type t1t ! type(tt), allocatable :: comp1 integer :: val !contains ! final bar1 end type t1t type, extends(t) :: t2 type(tt), allocatable :: comp2 contains