F2003 Finalization -- progress and problems

Daniel Kraft d@domob.eu
Tue Jun 10 18:48:00 GMT 2008


Tobias Burnus wrote:
>> After finishing the code, I want to write some little documentation
>> about how finalization works and is implemented if you want so in the
>> future everyone has it easier to work on it (now that I still know how
>> it works...), if you point me where to write this.
> GREAT idea! I think gfc-internals.texi is the best place, see:
> http://gcc.gnu.org/onlinedocs/gfc-internals/
> (An alternative would be the Wiki, but I think gfc-internals.texi is 
> better.)

I also like the TexInfo better, so we've agreed here ;)  But this will 
have to wait until the code is ready for check-in I think, then we can 
discuss this again.

>> c) what exactly does that "specification expression in scoping unit"
>> mean?  But otherwise, this sounds similar to b).
> 
> "If a specification expression in a scoping unit references a function, 
> the result is finalized before execution of the first executable 
> statement in the scoping unit."
> 
> "7.1.6 Specification expression"
> "R729 specification-expr is scalar-int-expr"
> "C710 (R729) The scalar-int-expr shall be a restricted expression."
> "A *restricted expression* is an expression [...], and where any final 
> subroutine that is invoked is *pure*."

But then nothing needs to be finalized if the result has to be 
integer...  Or did I miss something?

>> b) results of functions and structure-constructors after they have been
>> used:  I'm not sure how this could be done in resolution-phase (without
>> "rewriting" the code and introducing temporaries), but maybe in trans
>> this will be easier.  Any ideas and tipps? 
> I don't quite understand what with "after they have been used" is meant 
> - nor can I find it in the standard. (Currently, I have no opinion 
> whether on should use trans*.c or resolve*.c.)

In the subsection "When finalization occurs":

...

"If an executable construct references a function, the result is 
finalized after execution of the innermost executable construct 
containing the reference.

"If an executable construct references a structure constructor, the 
entity created by the structure constructor is finalized after execution 
of the innermost executable construct containing the reference."

My problem here is that if we have something like:

x = foobar (funct (x)),

where funct returns a finalizable entity.  Then we need to generate code 
like that:

temp = funct (x)
x = foobar (temp)
finalize (temp)

If I did understand the code correctly.  Are such nested constructs 
flattened in trans like the above or is this passed down like it is to 
the middle-end and converted there?  In the latter case, we would need 
to split it and introduce temporaries manually during either resolution 
or trans to handle the finalization (in that case when both are equally 
possible, I'd prefer resolution as working on the gfortran-trees is 
probably easier as more information is available).  Or do you have 
better ideas?

I think it should not be too hard to do those splitting of expressions, 
although it surely makes the code uglier, but I don't see any other way 
to handle the finalization-requirements of the standard.

>> e) intrinsic assignment: for ordinary assignments this is handled
> What do you mean by ordinary assignments? If you mean a simple

Right, I mean assignment not in WHERE/FORALL; I believe somewhere in the 
code this is called "resolve_ordinary_assignment" ;)

>  type(t) :: x, y
>  y = x
> 
> then this is an intrinsic assignment unless you have "assignment(=)" 
> anywhere. Using
> 
>  interface assignment(=)
>      subroutine assign_t(x,y)
> 
> the finalization happens automatically as the LHS argument matches a 
> INTENT(OUT) in assign_t.

Ah, yes!  But I have to make sure the LHS is not finalized twice in this 
case; the old patch *should* already handle this, but at the moment 
there's no test for this.  That will be changed of course.

>> WHERE (arr == 2)
>>      arr = 5
>> END WHERE
>>
>> Should this finalize the whole masked arr at once or each element before
>> it is overwritten?  Can there be a similar unclarity for FORALL?
> I really dislike WHERE as it is (at least to me) a bit intransparent 
> what happens there. Maybe something to ask at lang.comp.fortran.

I myself don't have much experience with WHERE, only looked at it 
briefly once.  From a programmer's point of view, it sounds nice to me 
(or, better, like a neat feature that let's you express some thing in an 
elegant way; but it might be something that's never really needed 
anyway, I don't know).  But I believe this will be some mess implementing...

> I read this as follows, but now guarantees that I interpret the standard 
> correctly.
> 
> {
>  tmp = function(array)
>  finalize(array(mask))
>  array(mask) = tmp(mask)
> }

That makes sense, so finalizing the masked array.

> FORALL: I have not yet fully understand how this should be handled, but 
> note:
> 
> "C738 (R756) Any procedure referenced in a forall-body-construct, 
> including one referenced by a defined operation, assignment, or 
> *finalization*, shall be a *pure* procedure."
> 
> And for PURE procedures:
> 
> "C1273 Any procedure referenced *in a pure subprogram*, including one 
> referenced via a defined operation, assignment, or *finalization*, shall 
> be *pure*."

Do you mean I have to check on finalization if the only calls are pure 
procedures and output an error otherwise?  Hm...  It gets even nicer...

>> I was more thinking about the expression "x + foobar (x)" in itself 
>> rather than the I/O; that's because foobar (x) changes the value of x 
>> and I wanted to know whether it was defined or not if the first x had 
>> the earlier or later value.
> 
> In other words: The program is invalid and the compiler can do anything. 
> (The saying goes this includes starting WW3.)

Thanks, that's what I was looking for.

>>> +    TYPE(yes_t), ALLOCATABLE :: alloc_vector(:)
>>> +    ! alloc_vector is deallocated automatically here
>>> +    ! XXX: Or not?
>>
>> BTW, I was a bit surprised when I first read about this nice feature 
>> of automatic deallocation (and automatic allocation the like)--Fortran 
>> isn't C++ :D
> That is one of the nice features of Fortran: With allocatable, one 
> cannot have loose memory. If one tries to allocate an already allocated 
> variable, one gets an error; and when the variable goes out of scope, it 
> is automatically deallocated.

This is implemented now, I did this other than everything else so far in 
trans as I believe this automatic deallocation is added there.

How about ALLOCATABLE components?  I saw in the code there that all 
those are recursively deallocated during deallocation of an entity.  So 
this means we have to finalize those, too, before they get deallocated, 
right?  But maybe this isn't much effort now I've already some 
experience (and code) for doing the finalization in trans.

The problem with this is just that I need the original gfc_expr for 
this, as I have to have access to the derived-type structure and similar 
for access to the finalizer-procedures and the like.  And this lets me 
reuse the existing finalization-code :D

Cheers,
Daniel

-- 
Done:     Bar-Sam-Val-Wiz, Dwa-Elf-Hum-Orc, Cha-Law, Fem-Mal
Underway: Ran-Gno-Neu-Fem
To go:    Arc-Cav-Hea-Kni-Mon-Pri-Rog-Tou



More information about the Fortran mailing list