Print

Print


>
I figured this might be a more useful forum than private email, and there was always a chance that someone else could save Malcolm the time from crafting a response.


So instead I have to read through over a dozen emails and redo my analysis and compare with what everyone else is saying?  And with the new version of the code instead of the one you sent us, so I cannot be sure that my analysis still holds?

I think I will pass on that.  I scanned them, and your sample program, and it looks like my analysis still holds ...

I did explain precisely what was going on to my colleague who asked, in gory detail.  None of it was to do with any complicated new semantics, and all of it was bog-standard “uses a Fortran 90 feature wrongly and does not conform to any Fortran standard” (we have not changed the semantics of defined assignment).  Since you are still asking questions it would seem that my colleague rather cut too much out of my reply – that is unfortunate and I apologise.  (I was on holiday so my reply although detailed was pretty roughly worded, and also included a load of irrelevant side issues.)

I will copy-paste from the code you sent us which is quite clear:

! The line below shows the problem
!   v = array
! The line below avoids it
!   call v%copyFromArray(array)

My response is to add two extra lines:
! This line shows the problem is a bug in the program
   call v%copyFromArray((array))


The semantics of defined assignment is that “v = array” is equivalent to the line in my addition, not your line.  This means that the second actual argument to the defined assignment routine is an expression, not a variable, and does not have the TARGET attribute.

Then by the normal argument association rules, a pointer associated with a dummy argument with the TARGET attribute, when the actual argument has the TARGET attribute, becomes undefined on return from the procedure.  This is not just a theoretical consideration, since in many (most?) cases the compiler will need to make a copy of “array” so that when the LHS and RHS of the defined assignment overlap, it still gives the right answer.

You might or might not notice this with your test program since
  1.. it is conceivable that the compiler could have discovered that there was no aliasing potential and therefore optimised-out the copy, 
  2.. the compiler does not implement the correct semantics for defined assignment, as in, does not parenthesise the RHS, 
  3.. the compiler does not implement the correct semantics for parenthesised expressions when allocatable components are concerned (as in, does a shallow copy instead of a deep copy – yes this would be visible in a standard-conforming program), or 
  4.. the pointer is pointing to deallocated memory that has not been reused and still has the same contents as before.
In the case of the NAG compiler, number 1 does not apply as we don’t attempt to optimise away the copy in this situation (there are too many chances to get it wrong!), numbers 2 and 3 do not apply as we do copying, with deep copying for allocatable components, and number 4 does not apply as our memory allocator overwrites the first 8 bytes of a deallocated memory block.  I would guess that reason 4 is the most likely reason your test does not fail on the Intel compiler.  Note however that in a “real program” this is highly likely to eventually fail catastrophically with no clues as to what went wrong as you will have different variables unintendingly sharing memory – whether that is by the pointers pointing to dead memory that gets reused, or if there is a compiler bug that does not copy things that need to be copied – cue mysterious memory corruption.

Here is what I wrote before:

BTW2, the faulty line is
               this%elements(i)%item => array(i)
... if the user wants to make a copy of the array he needs to make a copy of 
the array, not store pointers into the dummy argument - because of the 
parentheses, the actual argument does not have the TARGET attribute(!!!) and 
therefore, by (Fortran 2008) 12.5.2.4 paragraph 11(page 294 lines 21-23),
  "If the dummy argument has the TARGET attribute and the effective argument 
does not have the TARGET attribute ... any pointers associated with the 
dummy argument become undefined when execution of the procedure completes."

BTW3, the parentheses are specified by page 285 lines 3-5
"A defined assignment is treated as a reference to the subroutine, with the 
left-hand side as the first argument and the right-hand side enclosed in 
parentheses as the second argument."

This text is basically unchanged since F90.  It is a bit of a pity that the defined assignment semantics are split between clause 7 and 12, but it was that way in F90 and we never changed it.  This probably deserves an editorial change in the next revision.  Someone else should remind me about this later as I have now spent double the time I should have done on this issue.

Cheers,
-- 
................................Malcolm Cohen, Nihon NAG, Tokyo.