From lrr@ironwood-fddi.cray.com Mon Apr 17 12:35:03 1995
Received: from timbuk.cray.com by dkuug.dk with SMTP id AA10453
  (5.65c8/IDA-1.4.4j for <sc22wg5@dkuug.dk>); Tue, 18 Apr 1995 00:35:08 +0200
Received: from sdiv.cray.com (ironwood-fddi.cray.com [128.162.21.36]) by timbuk.cray.com (8.6.9/CRI-fence-1.4) with SMTP id RAA05225 for <sc22wg5@dkuug.dk>; Mon, 17 Apr 1995 17:35:06 -0500
Received: from hickory317 by sdiv.cray.com (5.0/CRI-5.15.b.orgabbr Sdiv)
	id AA00811; Mon, 17 Apr 1995 17:35:05 -0500
From: lrr@ironwood-fddi.cray.com (Larry Rolison)
Received: by hickory317 (5.0/btd-b3)
          id AA08298; Mon, 17 Apr 1995 17:35:04 -0500
Message-Id: <9504172235.AA08298@hickory317>
Subject: A paper for the meeting
To: sc22wg5@dkuug.dk
Date: Mon, 17 Apr 1995 17:35:03 -0500 (CDT)
X-Mailer: ELM [version 2.4 PL24-CRI-b]
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Length: 51100     
X-Charset: ASCII
X-Char-Esc: 29

I hope that someone at the meeting in Tokyo is reading their email while at
the meeting.  Would anyone that is currently at the meeting please make a 
copy of the paper contained in this message and give it to Miles for 
submission to the meeting?  I understand that I am very late but this issue
is very important to myself, John Reid, and others.  I thank you in advance
for you help and indulgence in this matter.  I will be submitting the same
paper to the electronic premeeting for the X3J3 meeting.

----------------------------   cut   -----------------------------------------

To:  WG5
From:  Larry Rolison
Subject:  Correction to the current response for Interp 125
 
This is quite a long paper and deals with some complex issues (Interpretation
125 again) but PLEASE bear with me because the response to 125 (already in a
Corrigendum unfortunately) has broken the standard.  It is CRITICAL that this
get fixed before we submit the standard for balloting.  I'm sorry that it's
taken me so long to get this to both WG5 and X3J3.  I fully understand that
it is the 11th hour of fixing the standard but my "real" job at Cray of 
producing a Fortran 90 updated compiler has kept me exceedingly busy for 
weeks.  But that is something I'm sure all compiler writers could say...

This is the message that Janice sent out in mid-February that started me, 
John Reid, and others to reconsider the response to Interp 125:

   --------------      Begin Janice's message      ---------------

Date: Tue, 14 Feb 95 19:14:15 EST
From: "Janice Shepherd" <JANSHEP@torolab2.vnet.ibm.com>
To: x3j3@ncsa.uiuc.edu
Subject: (x3j3.1995-62) defect item 125

Let us consider again the ramifications of the answer to defect item 125.

For the purposes of this discussion I would like to use the
term "TARGET array dummy argument" to mean a dummy argument that
is an array and has the TARGET attribute.

It appears to me that to get the semantics required by defect item 125
arguments passed to a TARGET array dummy argument must be passed by
descriptor (also known as dope vector).

Currently I believe that most of the implementations pass such
arguments by address (unless the array is assumed-shape). There
is some variation as to whether it is the address of a copy of the
actual argument that is passed or the address of the argument itself.

The reason a descriptor is needed can be seen by the following example:

   integer, pointer :: p(:)
   integer, target :: t(10)
   interface
     subroutine sub(targ,parg)
       integer, pointer :: parg(:)
       integer, target :: targ(5)
     end subroutine
   end interface
   p => t(2:10:2)

   call sub (t(2:10:2),p)
   end

   subroutine sub(targ,parg)
     integer, pointer :: parg(:)
     integer, target :: targ(5)
     write(6,*) associated(parg,targ)
   end

Defect item 125 requires that the value written by 'sub' be .TRUE..
If an implementation wants to pass the argument by address then
a copy of the non-contiguous array section must be made, as only
contiguous arrays can be passed by address. When a copy is made,
pointer 'p' will not be associated with the copy and 'sub' will
write out .FALSE. instead of .TRUE. Thus a copy must NOT be
made and the information about the strides of the section must
be communicated to the dummy argument via a descriptor.

Difficulties of passing by descriptor arise if the actual argument
does not have the TARGET attribute and does not have the same
shape as the dummy argument. Recall that defect 125 includes the
following edit:

1. Section 12.4.1.1, add at the end of the fourth paragraph [173:6],

      "If the dummy argument has the TARGET attribute and the actual
       argument has the TARGET attribute but is not an array section
       with a vector subscript, the dummy and actual arguments must
       have the same shape."

Given an interface such as:
   interface
     subroutine sub(targ,n)
       character*(n), target :: targ(n+5, n-4, n:*)
     end  subroutine
   end interface

and given declarations such as the following

   character*(10) :: not_target_1(100), not_target_2(10,*)

then valid calls to sub include:

   call sub(not_target_1, i)

   call sub(not_target_1(j), i)

   call sub(not_target_2(j,k), i)

where 'i' determines the character length of the dummy argument and
the extents of the dimensions. Setting up the descriptor is no
longer straight forward. It becomes quite complicated.

When we approved defect 125, did we really mean implementations to
go to all this extra work?

I can see several possible "edits" that would greatly simplify the
situation.

 1) Change the edit I've shown above to the following:

      "If the dummy argument has the TARGET attribute and is an array,
       the dummy and actual arguments must have the same shape."

    This would keep the set up of descriptors straight forward.

or

 2) Change which pointers become associated with TARGET dummy arguments:

    Defect item 125 adds the following text to section 12.4.1.1

      " If the dummy argument has the TARGET attribute and the
        corresponding actual argument has the TARGET attribute but
        is not an array section with a vector subscript:

          (1) Any pointers associated with the actual argument
              become associated with the corresponding dummy argument
              on invocation of the procedure.

          (2) When execution of the procedure completes, any
              pointers associated with the dummy argument remain
              associated with the actual argument.

        If the dummy argument has the TARGET attribute and the
        corresponding actual argument does not have the TARGET
        attribute or is an array section with a vector subscript,
        any pointers associated with the dummy argument become
        undefined when execution of the procedure completes."

    Change this text so that pointers associated with non-contiguous
    actual arguments do NOT become associated with TARGET dummy
    arguments. Thus simple pass by address could be used.
    Copies would be used for non-contiguous arrays. (Remember pass
    by address is what most implementations are doing right now, it is
    just the occurrence of making a copy that is inconsistent right now.)

    Note that scalars are always contiguous, so that if a pointer is
    associated with a scalar TARGET actual argument that is passed to a
    scalar TARGET dummy argument, the pointer will be associated with
    the dummy argument.

 3) Change which pointers become associated with TARGET dummy arguments:

    Change the text shown in choice (2) so that whether a pointer
    is associated with a TARGET array dummy argument is processor
    dependent.

    A bit of a cop-out, but it at least reflects the current state
    of affairs. If may be easier to implement for some than choice (2)
    as not all implementations track whether an array is contiguous
    or not.

I've discussed this item briefly with John Reid, during which I
had only thought of solution (1). John is very much against (1) as
he feels that many people take advantage of being able to pass a
non-target array element to a TARGET array, or being able to pass
a non-target array of one shape to a TARGET array of a different
shape. His concern led me to include the other 2 proposals.

By the way, an implementation must choose one passing method for
a given dummy argument. If the dummy argument is expecting a
descriptor all calls must pass a descriptor for that dummy argument.
If the dummy argument is expecting an address then all calls must
pass an address.

Thoughts on all of this?

Thanks.
Janice

             ----------    End Janice's message    ----------


John Reid and I have sent several messages back and forth discussing how to 
fix 125.  At first he felt that the standard should be left alone:

  From a February 16 message to X3J3 and Janice:

    If the actual argument does not have the TARGET attribute and setting
    up the descriptor is not straight forward, surely the implementation
    is free to make a copy and construct a descriptor for the copy.

    Please let's not change 125.
 
but then after discussing the problem further he jumped in with rest of us to
provide a solution to the problem rather than ignoring it.  However, he was
on assignment in Australia and his assignment expired on April 6 I believe. 
Following that time, he and Alison were going to be on vacation until April
24.  John had the good sense to NOT take any kind of computer with him on his
vacation so he will have not email contact until April 24.  This means that
our discussion was cut short.  Although we were converging on a single updated
response to 125, John has not seen the final material I have below.  However,
I am confident he would agree with its direction, but as usual, might have
some rewording suggestions to make it more precise.  Given the timing of his
vacation and the WG5 and X3J3 meetings, we will have only a small window of
opportunity to get his help.

 
The following is the central premise around which I will build my arguments
for correcting the response to 125.

   If a pointer is associated with a target and both the pointer and
   the target are passed to corresponding pointer and target dummy
   arguments, the pointer must still be associated with the target in
   the called procedure and, if the dummy pointer is still associated
   with the dummy target at the end of the called routine, then the
   actual pointer remains associated with the actual target upon return
   to the calling procedure.

This requirement is currently a part of the response to 125 and it must be
maintained.  (The question that Janice poses is essentially "When are the
actual pointer and target arguments passed and when is the pointer and a 
temp passed?"  Interp 125 tried to answer that question and got it wrong.
This paper will attempt to correct that error.)

A small cautionary digression:  remember that accessing an array via a
descriptor is significantly slower than accessing it by direct addressing.
To put it simply:  use of descriptors may significantly decrease execution
performance.  You will see as this paper progresses that I will attempt to
avoid use of descriptors wherever possible (especially places where the
programmer might cause them to be generated and used unexpectedly and
unnecessarily).

Janice chose to deal only with the "interesting" case of a dummy target that is
an array so I will do the same.  I will continue her use of the term "target
array dummy argument" to mean a dummy argument that is an array and has the
TARGET attribute (I have just not capitalized "target" in phrase since this
usage is not referring directly to the TARGET attribute or statement).

As a way of introduction, I'll quote some of Janice's initial statements:

   It appears to me that to get the semantics required by defect item 125
   arguments passed to a TARGET array dummy argument must be passed by
   descriptor (also known as dope vector).

   Currently I believe that most of the implementations pass such
   arguments by address (unless the array is assumed-shape).  There
   is some variation as to whether it is the address of a copy of the
   actual argument that is passed or the address of the argument itself.

I agree with her first statement in that it appears to get the semantics
required by THE CURRENT ANSWER TO DEFECT ITEM 125 arguments passed to
EXPLICIT-SHAPE target array dummy arguments MUST BE PASSED BY DESCRIPTOR.
Janice also points out that since the actual must be passed by descriptor, the
target array dummy argument must also be represented by a descriptor EVEN IF
IT'S EXPLICIT-SHAPE.  I contend the committee has committed a serious error
in trying to force these semantics.  This is where Janice and I part company:
where I contend the current answer to 125 must be thrown out, Janice is trying
to add more rules to the current answer to 125 to try to get it to "work".  I
contend that we can NOT fix this by adding more rules because the underlying
notion of representing an explicit-shape array via a descriptor is fatally
flawed.

I also agree with her second statement.  Our compiler (right now) as a matter
of fact passes actual array arguments by address to explicit-shape target array
dummy arguments.  Because it does so (and has not changed yet to accomodate
the current response to Interp 125), we will get some argument passing cases
wrong, as will every other vendor that passes by address in this case.  The
failure can't be helped; information that the current answer requires inside
the called procedure is simply not available when a descriptor does not exist.

I'll now go through each of the relevant array bound declaration methods and
try to show the ramifications of the answer to defect item 125 in relation to
each of the declaration methods, why the response to 125 is wrong, and how to
fix it.


Assumed-shape
-------------

Normally, when discussing array dummy arguments in general, one might leave
assumed-shape arrays until the last (working from easy to hard) because they
generally involve extra considerations.  For the purposes of discussing Interp
125, the "extra considerations" are exactly what we're talking about:  the
necessity for descriptors.  So in this case, we can dismiss target array
dummy arguments that are assumed-shape because they need to be addressed via
descriptors by definition (the TARGET attribute is irrelevant).


Explicit-shape
--------------

The following is an expansion of Janice's example:

   INTEGER, TARGET  :: t5(5), t10(10)
   INTEGER, POINTER :: p(:)

   INTERFACE
     SUBROUTINE sub(targ, parg)
       INTEGER, TARGET  :: targ(5)
       INTEGER, POINTER :: parg(:)
     END SUBROUTINE
   END INTERFACE

   p => t5
   CALL sub (t5, p)

   p => t10(2:10:2)
   CALL sub (t10(2:10:2), p)

   END

   SUBROUTINE sub(targ, parg)
     INTEGER, TARGET :: targ(5)
     INTEGER, POINTER :: parg(:)
     WRITE(6,*) ASSOCIATED(parg, targ)
   END

Note that the first call to SUB passes an array (T5) that has contiguous
storage, where the second call passes an array (T10(2:10:2)) that has
noncontiguous storage.  And, more importantly, notice that both of these
actual arrays are passed to an EXPLICIT-SHAPE dummy array.  And most 
importantly, notice that nowhere in this paragraph did I use either the 
word "pointer" or the word "target".  That is because (and you're going to
hear me say this a bunch of times) 

      When passing an array actual argument to an array dummy argument,
      whether or not a temp is produced is COMPLETELY independent of 
      whether or not either or both the actual and dummy argument arrays
      have the TARGET attribute.

If the above example had been written as:

   INTEGER :: t5(5), t10(10)

   INTERFACE
     SUBROUTINE sub(targ)
       INTEGER :: targ(5)
     END SUBROUTINE
   END INTERFACE

   CALL sub (t5)

   CALL sub (t10(2:10:2))

   END

   SUBROUTINE sub(targ)
     INTEGER :: targ(5)
     WRITE(6,*) targ
   END
     
there would be no question in anyone's mind that the first call to SUB would
pass the address of T5 and the second call would produce a temp to hold the
values of T10(2:20:2) and the address of the temp would be passed.  Let me
say it again:

      When passing an array actual argument to an array dummy argument,
      the presence of the TARGET attribute is COMPLETELY IRRELEVANT when
      deciding whether or not a temp is required.


These examples demonstrate why the current response to 125 is not just wrong, 
but horribly wrong.  I spent a couple of hours with another front-end
programmer that did the descriptor code and had my eyes opened as to what
the committee had done to the language with respect to 125.  I'm terribly
sorry that it's taken me this long to see the light.  I thought I had a handle
on 125 but I was dead wrong.  And now I must try my level best to convince the
rest of you that what we've done is wrong and hopefully turn the light on for
some other committee members.

Where we have gone incredibly wrong is as simple as this:

   We now allow a declaration of an EXPLICIT-SHAPE array to represent
   NONcontiguous storage.

Throughout the history of Fortran (a programming language that's older than
some committee members), an explicit-shape array declaration, particularly one
involving only constants, such as

         INTEGER  a(5)

IN ANY CONTEXT has ALWAYS meant that the array's storage was contiguous and
no other attribute has ever affected the contiguousness or noncontiguousness
of that storage.  In fact, when X3J3 invented noncontiguous storage in Fortran
90, we specifically invented a new declaration symbol (<assumed-shape-spec>)
to indicate both to the human reading the program and to the compiler that the
storage for the array could be noncontiguous.  With the current state of
Interp 125, we have for the first time in Fortran history violated explicit-
shape array declarations in not one but several ways:

  (1) the meaning of an explicit-shape array bound, EVEN IF CONSTANT, is now
      context sensitive

  (2) a CONSTANT array bound might now represent noncontiguous storage

  (3) the determination of the meaning of the array bound EVEN IF IT IS A
      CONSTANT is dependent on another "special" attribute (TARGET)

I'll briefly explain the ramifications of these changes:

   *  In a main program, in a block data subprogram, or in the specification
      part of a module, an explicit-shape bound still means that the array is
      contiguous (which has the important corollary that a descriptor is not
      needed to reference it).  However, when an explicit-shape array
      declaration appears in an external subprogram, internal subprogram, or
      module subprogram, the explicit-shape array declaration MIGHT represent
      noncontiguous storage.  This has the important corollary that
      a target array dummy argument with an explicit-shape MIGHT be accessed
      via a descriptor EVEN IF THE BOUNDS ARE CONSTANTS.

      So if the context is a main program, block data subprogram, or module
      specification part, explict-shape has one meaning but if the context is
      a function or subroutine subprogram, an explicit-shape COULD mean
      something different (for both the user and the compiler).

   *  Janice's examples show that the current state of 125 requires that an
      explicit-shape array dummy argument must be able to represent both
      contiguous storage and noncontiguous storage EVEN IF ALL BOUNDS ARE
      CONSTANTS in some "special" cases.

   *  An explicit-shape array dummy argument MIGHT have to be able to represent
      both contiguous and noncontiguous storage to handle the case Janice cites
      even though the declared bounds of the array dummy argument are ALL
      constants.  But this "might" only comes into play if the array also has
      the TARGET attribute.  So for the first time in Fortran history an
      attribute other than a dimension declarator affects storage layout of
      an explicit-shape array.
      
I'm woefully disappointed in myself that I did not see this nor understand
its ramifications long ago.  Allowing this change to happen to explicit-shape
arrays is patently ludicrous for the language, for users, and for compilers.

The way to fix it is to follow the model of array declarations that we already
have.  It is the array bound declaration and ONLY the array bound declaration
that should determine the storage contiguity assumptions the compiler and user
may make.  That is, we MUST continue with the array declaration model that
Fortran has had since inception:  if an array is declared to be explicit-shape,
its storage is by definition contiguous.  In Fortran 90, if one wishes to
utilize an array whose storage might or might not be contiguous, then one must
declare the array to be assumed-shape.  That's the whole point of inventing
the assumed-shape spec (and a large part of the rules behind explicit
interface requirements).  This also does away with the untenable effect of the
TARGET attribute when declaring an array.  We simply must not let this
ephemeral connection between TARGET and array bound declarations stand.

Note that a large part of Janice's question and the response to 125 dealt with
shapes of the actual and dummy arrays, and tried to invent rules to prevent
problems.  If we simply go by the array bound declaration rules we already
have, all these shape matching problems and additional rules are unneeded.
The rules for assumed-shape arrays already work.

Thus, in Janice's example above, since the target dummy argument array is
declared to be an explicit-shape array, when the first actual argument is
passed, its storage is already contiguous so the result of ASSOCIATED in
subroutine SUB is true.  And, just like every other case of passing a
section to an explicit-shape array, when the section and its pointer are passed
to SUB, the result of ASSOCIATED in SUB is false (because the section had
to be copied to a contiguous temp).

This is exactly the behavior the user expects in every other case where a
noncontiguous array is passed to a contiguous array, so passing to a target
array dummy argument should be no different.  If the user really must be able
to pass both a contiguous array or a noncontiguous array to a target array
dummy argument, then they simply must declare the target array dummy argument
to be assumed-shape.  There is no surprise here.

In fact, we can just about get rid of the rule that if a dummy argument has
the TARGET attribute, the interface must be explicit.  Since the user would now
need to use an assumed-shape dummy argument when the actual argument might or
might not have contiguous storage, the explicit interface would already be
required.

This model also gets rid of all the questions about what happens when a
nontarget actual array is passed to a target dummy array.  The questions
simply become irrelevant because the fact that the TARGET attribute is involved
is irrelevant.  The rules for how an array is passed to another array are
based solely on the declaration or reference methods of the arrays.  All other
attributes are irrelevant; this was true before we went down this path
worrying about the TARGET attribute and it continues to be true.

Janice suggests 3 different fixes for this problem, all involving slight
changes to Interp 125.  Changing Interp 125 is unfortunate because it's
already been voted on and has passed WG5 but I believe it is something we MUST
do in order to get this whole mess straightened out.  (I really wanted to
add yet another harangue here about how much effort this committee has spent
in defining and redefining the most complex pointer model in the history of
computing but I think most of you could anticipate what I would say so I
won't bother.)

Due to my conclusion above that TARGET is irrelevant, I contend that none
of Janice's suggestions are viable.  The path we've been going down is wrong
and these suggestions continue that path and just try to bandage over what
we've done wrong.

There are two ways we can correct the answer to 125:

  (1) We can take the easy way out and say that a target dummy array argument
      must always be assumed-shape.

      This has the advantage that the compiler can easily detect TARGET and
      the wrong kind of array bounds specification.  It is good for naive
      users because it prevents them from getting answers from ASSOCIATED
      that vary from one call to another.  It has the disadvantage that it
      penalizes careful users that really do want to always pass contiguous
      storage to the target array dummy argument for performance reasons.

  (2) We can say that the result of ASSOCIATED in the called routine is
      dependent on the combination of the actual array's subscript list and
      dummy array's bounds.  The result of ASSOCIATED for classic examples
      such as Janice's can be described by the following table:

          Actual argument     |  Dummy argument       --> ASSOCIATED result
          =================================================================
          Cont. seq. array*   |  Cont. seq. array     --> .TRUE.
          -----------------------------------------------------------------
          Noncont. seq. array |  Cont. seq. array     --> .FALSE.
          -----------------------------------------------------------------
          Cont. seq. array    |  Assumed-shape array  --> .TRUE.
          -----------------------------------------------------------------
          Noncont. seq. array |  Assumed-shape array  --> .TRUE.
          -----------------------------------------------------------------

       * A "contiguous sequence array" is defined to be an array whose array
         elements storage units are contiguous and whose array elements are
         selected in array element order.  For example,

               array
               array(2:10)
 
         are contiguous sequence arrays but

               array(2:10:2)
               array(10:1:-1)

         are noncontiguous sequence arrays.


      Thus, passing an actual array such as ACTUAL(2:10:2) to a dummy array
      such as DUMMY(5) is passing a noncontiguous sequence array to a 
      contiguous sequence array.

      Note that an array dummy argument is a contiguous sequence array if 
      it is either explicit-shape or assumed-size (note I said "-size").

      In other words, any time the compiler needs to build a temp to represent
      the actual argument, you lose the association of the pointer with the
      actual argument and ASSOCIATED returns false in the called procedure.

      This has the advantage that it allows a careful, knowledgable user that
      wants to use pointers across a call yet retain as much execution
      performance as possible do so if the storage being passed is always
      contiguous (such that the target array dummy argument can be declared
      to be explicit-shape and thus use the fastest possible access method).
      It does not penalize users that understand the language.  It has the
      disadvantage that it could produce different answers for ASSOCIATED in
      the called procedure depending on the contiguity of the array that was
      passed to an explicit-shape target dummy array.  BUT those different
      answers are a direct result of the combination of arrays the user has
      specified.  The different answers will not surprise any reasonably 
      knowledgeable user.

Before providing the edits to fix the response to Interp 125, I'll continue
with the descriptions of the other array bound declaration methods.


Assumed-size
------------

I looked through the standard, particularly in sections 5.1, 5.1.2.2.4,
5.1.2.8, and 5.2.8 and could not find any rules prohibiting a target array
dummy argument from being assumed-size.  Therefore, I must assume that such a
combination of attributes is permitted.  What then, I asked myself, given the
current state of Interp 125 is the meaning of:

   INTEGER, POINTER :: p(:)
   INTEGER, TARGET  :: t5(5), t10(10)

   INTERFACE
     SUBROUTINE sub(targ, parg)
       INTEGER, TARGET  :: targ(*)
       INTEGER, POINTER :: parg(:)
     END SUBROUTINE
   END INTERFACE

   p => t5
   CALL sub (t5, p)

   p => t10(2:10:2)
   CALL sub (t10(2:10:2), p)

   END

   SUBROUTINE sub(targ, parg)
     INTEGER, TARGET :: targ(*)
     INTEGER, POINTER :: parg(:)
     WRITE(6,*) ASSOCIATED(parg, targ(1:5))
   END

To take the devil's advocate point of view with respect to the current state
of Interp 125, if one can pass contiguous or noncontiguous storage to an
explicit-shape array dummy argument (which has always been defined to have
contiguous storage) then surely one must be able to do the same thing with an
assumed-size array dummy argument (which has always been defined to have
contiguous storage).  And if the current state of Interp 125 declares that
T10(2:20:2) maps on to TARG(1:5) of TARG(5), then it is equally likely that
a user would think that T10(2:20:2) maps on to TARG(1:5) of TARG(*).  And if
the current state of Interp 125 declares that an explicit-shape target array
dummy argument must have a descriptor in order to provide the "correct" result
from ASSOCIATED, then surely it likewise means that an assumed-size target
array dummy argument must have a descriptor in order to get the "correct"
result from ASSOCIATED.

So then as an implementor, I ask myself:  if an assumed-size target array
dummy argument must have a descriptor, pray tell what goes in the extent
field of the descriptor for the last dimension?

So, this notion of an array that for the history of Fortran has represented
contiguous storage can suddenly by the simple addition of the TARGET attribute
represent noncontiguous storage just gets sillier and sillier.


Summary
-------

The storage of an explicit-shape array has always been contiguous by definition
in all contexts and must continue to be so.  In Fortran 90, the considerations
for passing an actual array to a dummy array have always depended solely on
the descriptions of the actual array's subscripts and the dummy array's bounds
and must continue to do so.  We have gone down the wrong path by trying to
change the meaning of array bound declarations in certain contexts in the
presence of the TARGET attribute.  The TARGET attribute is irrelevant in these
considerations and Interp 125 should be answered as such.

I believe this is a CRITICAL change to Interp 125 and MUST be made at the
April WG5 and X3J3 meetings.  We can not let the current answer to Interp 125
go into Fortran 95 and screw up the meaning of explicit-shape arrays for the
remainder of the life of Fortran.

Of the two solutions I present above, I prefer the second and the edits I 
present below reflect that choice.  This solution might bite the occasional
naive user but I think the language should be crafted for performance as
opposed to naive users.  This second solution provides the best of both worlds
to both kinds of users.  Beginners can be told to always declare target array
dummy arguments to be assumed-shape.  More sophisticated users can choose the
array bound declaration method that suits their application; if they can
guarantee that the storage being passed is always contiguous, then they're
free to gain maximum execution performance by declaring the target dummy array
argument to be explicit-shape.  If they can not guarantee the storage of the
actual argument to be contiguous on every call to the procedure inquiring
about pointer association, then they need to declare the target array dummy
argument to be assumed-shape.  Also, if a user that just wants to be able to
access a local explicit-shape target array dummy argument via a pointer and
that dummy argument is associated with a nontarget dummy argument, the user
can still reap the benefits of fastest possible access to the array dummy
argument.  This is an easy rule to remember and fits in with the array concepts
that already exist in the language.


Background on the edits
-----------------------

The key change we need to make to 125 is to describe the conditions producing
a temp when an actual array is passed to a dummy array argument.  We need to do
this so we can say "when a temp is generated to represent a target array, you
lose the pointer that was associated with the original target".  But 
obviously, we can not use the word "temp" in the standard so we need to find
a "standardese" way of describing when such temps are produced.  I will do
this via modifying the concept of sequence association.

12.4.1.4 defines sequence association.  Actually, the term "sequence
association" unfortunately only appears in the section heading (and a couple
of other places referencing the section) and is not actually defined anywhere.
The standard does define "sequence associated" (but not in bold) in 12.4.1.4
and I suppose from that people can derive a definition for "sequence
association".  Anyway, sequence association gets us part way to determining
when a temp is generated and when it is not by:

  * describing an element sequence

    Although the element sequence definition helps by saying the elements
    must be in array element order, it does not restrict the definition
    enough for what we want because it does not say that all elements
    in the sequence must be contiguous.

  * describing sequence association

    Again, this says what happens when an actual argument's storage is
    element associated with an explicit-shape or assume-size dummy
    argument but allows the ranks and shapes to differ.  We don't want
    these to differ (to insure that no temp is generated).

So what need to do is to describe a kind of sequence association that is more
restrictive than the sequence association currently defined by the standard.
If we can establish a definition for this restricted sequence association such
that it defines a "contiguous sequence array" as described above, then we
can determine (by that definition and the combination of actual and dummy
arguments) whether or not a temp is generated at the call site.  We can do 
this in standardese by describing in words the table I provided above.  Once we
know whether or not a temp is generated, we can determine whether or not
pointer association is preserved across the call.

But as a part of introducing this new restricted form of sequence association,
we also need to be careful NOT to force a compiler to determine at run time
whether or not an array is a contiguous sequence array.  This determination
CAN be made but we must leave it as a "quality of implementation" issue rather
than force all processors to be capable of doing the work at run time.  
Example:

          CALL sub( a(1:10:n) )

The section of A being passed is a contiguous array if the value of N is 1,
and is a noncontiguous array for any other value.  This is a VERY simple
example (don't forget, N could be an arbitrarily complex expression).  I 
do NOT want to force all Fortran 90 processors to have to generate code (or
worse yet, call a library routine) to evaluate every section subscript
(including every stride expression) at run time to detect whether or not the
array needs to be copied or its address can be passed every single time an
array section is passed to an explicit-shape or unknown shape array.  If an
array section involves any variables, I want a processor to be free to just
say "oh, it's an array section being passed to an explicit-shape array or an
unknown array, so I'll just copy it to a temp because a section subscript
contains a variable."  Otherwise, you'd be sentencing ALL processors to
completely evaluate all section references of the form    ARRAY(I:J:K, ...)
for all subscripts in the list to see if they conform to the "contiguous
storage" definition at run time.  Don't forget that some manufacturers extend
the number of dimensions so for them the burden would be even greater.  I want
to allow (and I think we MUST allow) a processor to NOT have to generate such
run-time investigatory code.  I want a processor to have the shortcut available
to simply copy the section if any of the triplets or the final subscript
contain/are variables and the receiving dummy argument is not assumed-shape or
is unknown.  I want this to be a quality of implementation issue rather than
rammed down processor's throats by the standard.

And, yes, this means that for an example like Janice's where the user does
something stupid like

         p => targ(2:20:n)
         CALL sub(targ, parg)

and passes TARG to an explicit-shape target array dummy argument, the 
result of ASSOCIATED within SUB will not only be processor-dependent, it may
well vary from one call to another depending on the value of N.  At first 
blush, this may seem horrible, but in actuality it is entirely the fault of
the user due to making the basic mistake of declaring the dummy argument array
to be explicit-shape.  I'll say it one more time to drive the point home:  If
a user REALLY wants to be able to sometimes pass contiguous storage to the
dummy argument array and sometimes pass noncontiguous storage AND retain the
pointer associated with the array actual argument, then they MUST declare the
dummy argument to be assumed-shape.  If it is declared as such, the result of
ASSOCIATED within SUB will always return the "expected" results.

As John wrote to me in one of our exchanges when discussing edits:

  I wish there were not so many edits, but once the new definitions are
  out of the way, it is a simplification.

I agree and I hope you will, too.


Edits
-----

  1. Insert as the first paragraph of 12.4.1.4 [174:1+]:

       There are two kinds of sequence association:

         (1) a general sequence association defined by a general element
             sequence.  This form allows the selected elements to be
             noncontiguous and allows the rank, shape, and character
             element lengths of the actual and corresponding dummy arguments
             to differ.

         (2) a contiguous sequence association defined by a contiguous
             element sequence.  This form restricts the selected elements
             to be contiguous and adds the further restriction that the
             shape and character element lengths of the actual and
             corresponding dummy argument must agree.

  2. In the first sentence of the first paragraph of 12.4.1.4 [174:2],
     change "represents an" to "represents a general (unrestricted)". 
     The words "general (unrestricted)" need not be bold.
 
  3. Following the third paragraph of 12.4.1.4 [174:13+], insert the
     paragraphs:

       An actual argument represents a <<contiguous element sequence>>
       if it is an array expression where the storage sequence of all elements
       selected is contiguous, an array element designator, or an
       array element substring designator.  If the actual argument is
       an array expression, the element sequence consists of the elements
       in array element order where the subscript order of each element
       must differ from the subscript order of the next element by 1.  If
       the actual argument is an array expression that is an array section,
       the last <section-subscript> must be a <subscript-triplet> with a
       <stride> value of 1 or a <subscript> and each other
       <section-subscript> must be a <section-triplet> with a <stride>
       value of 1 that selects the whole of the corresponding dimension of
       the array.  If the actual argument is an array element designator,
       the element sequence consists of that array element and each
       element that follows it in array element order.

       If the actual argument is of type character, the value of the
       length type parameter of the actual argument must agree with the
       that of the corresponding dummy argument.

       An actual argument that represents a contiguous element sequence
       and corresponds to a dummy argument that is an array-valued data
       object is contiguously sequence associated with the dummy argument
       if the dummy argument is an explicit-shape or assumed-size array.
       The shape of the actual argument must agree with the shape of the
       dummy argument.  If the dummy argument is assumed-size, the number
       of elements in the dummy argument is exactly the number of elements
       in the contiguous element sequence.

  4. Change the following sentence from 12.4.1.1, fifth paragraph [173:10-13].
     I quote the original sentence from the Fortran 90 standard.  This 
     sentence has already been altered by 125 and already is in a Corrigendum.
     That is unfortunate but is hardly a reason for not fixing the standard,
     the response to 125, and the Corrigendum.

       When execution of the procedure completes, the pointer association
       status of the dummy argument becomes undefined if it is associated
       with a dummy argument of the procedure that has the TARGET
       attribute or with a target that becomes undefined (14.7.6);
       following this, the pointer association status of the actual
       argument becomes that of the dummy argument.

     to

       When execution of the procedure completes, the pointer association
       status of the dummy argument becomes undefined

         (1) if it is associated with another dummy argument of the
             procedure where that other dummy argument is not contiguously
             sequence associated (12.4.1.4) with its corresponding actual
             argument, or

         (2) if it is associated with a target that becomes undefined
             (14.7.6);

       Following this, the pointer association status of the actual
       argument becomes that of the dummy argument.

  5. Replace the fifth paragraph of 12.4.1.1 [173:14-17] with the following
     paragraphs:

       If the actual argument has the TARGET attribute and the corresponding
       dummy argument does not have the TARGET attribute, any pointers
       associated with the actual argument do not become associated with
       the dummy argument.

       If the both the actual argument and the corresponding dummy argument
       have the TARGET attribute and the actual argument is contiguously
       sequence associated with the corresponding dummy argument (and the
       processor can detect this association) or the dummy argument is
       assumed-shape, any pointers associated with the actual argument are
       associated with the dummy argument upon invocation of the procedure.
       Note that it is processor-dependent whether or not a processor can
       determine on any given invocation of the procedure whether or not
       an actual argument is contiguously sequence associated with the
       corresponding dummy argument.  When the execution of the procedure
       completes, any pointers associated with the dummy argument that are
       also accessible to the invoking procedure remain associated with the
       actual argument if the dummy argument is assumed-shape or if the
       processor detected that the actual and dummy arguments were
       contiguously sequence associated.

       If the actual argument does not have the TARGET attribute but the
       corresponding dummy argument does have the TARGET attribute, any
       pointer associated with the dummy argument becomes undefined when
       execution of the procedure completes.

  6. Replace the second paragraph to the end of C.12.8 with the following:

       As noted in 12.4.1.1, there are three combinations possible for
       an actual argument and a corresponding dummy argument with respect
       to the TARGET attribute:

          (1) The actual argument has the TARGET attribute but the
              corresponding dummy argument does not.

          (2) Both the actual and corresponding dummy arguments have the
              TARGET attribute.

          (3) The actual argument does not have the TARGET attribute but
              the corresponding dummy argument does.

       In the first case, since the dummy argument does not have the TARGET
       attribute, no pointer can become pointer associated with it.  In
       particular, this means that any pointer associated with the actual
       argument is not associated with the dummy argument.  An example of
       this is:

              REAL, TARGET  :: ARRAY(10)
              REAL, POINTER :: P(:)
              P => ARRAY
              CALL TEST (P, ARRAY)
              CONTAINS
                SUBROUTINE TEST (Z, ARR)
                  REAL, POINTER :: Z(:)
                  REAL          :: ARR
                  IF (ASSOCIATED(Z, ARR)) ...
                END SUBROUTINE
              END

        Since array dummy argument ARR does not have the TARGET attribute,
        pointer Z can not possibly be associated with it so ASSOCIATED returns
        false.

        In the second case, since both the actual and the corresponding
        dummy arguments have the TARGET attribute, any pointer that is
        associated with the actual argument and that is accessible to both
        the invoking and invoked iprocedures is generally associated with
        the dummy argument (the exceptions are noted below).  If any such
        pointers remain pointer associated with the dummy argument when
        execution of the procedure completes, they remain associated with the
        actual argument.

        When the actual and dummy arguments are arrays, pointer association
        is preserved across the procedure invocation only if (a) the actual
        and dummy arguments are contiguously sequence associated or (b) if
        the dummy argument is assumed-shape.  It is processor-dependent as
        to whether or not on any given invocation the processor determines
        that the arrays are contiguously sequence associated.  An example of
        this is:

              INTEGER       :: I, J, K
              REAL, POINTER :: PTR1(:,:), PTR2(:,:)
              REAL, TARGET  :: ARRAY(10,10)

              PTR1(2:10:2, :) => ARRAY(2:10:2, :)
              PTR2(2:10:2, :) => ARRAY(2:10:2, :)
              CALL A_S_SUB (PTR1, ARRAY(2:10:2, :))

              CALL E_S_SUB (PTR1, ARRAY(2:10:2, :))

              READ *, I, J, K
              PTR1(I:J:K, :) => ARRAY(I:J:K, :)
              PTR2(I:J:K, :) => ARRAY(I:J:K, :)
              CALL E_S_SUB (PTR1, ARRAY(I:J:K, :))

              CONTAINS

                SUBROUTINE A_S_SUB (ASP, ASARRAY)
                  REAL, POINTER :: ASP(:,:)
                  REAL, TARGET  :: ASARRAY(:,:)
                  IF (ASSOCIATED(ASP, ASARRAY)) ...
                  IF (ASSOCIATED(PTR2, ASARRAY)) ...
                END SUBROUTNE

                SUBROUTINE E_S_SUB (ESP, ESARRAY)
                  REAL, POINTER :: ESP(:,:)
                  REAL, TARGET  :: ESARRAY(5,10)
                  IF (ASSOCIATED(ESP, ESARRAY)) ...
                  IF (ASSOCIATED(PTR2, ESARRAY)) ...
                END SUBROUTINE

              END

        The first result of ASSOCIATED in A_S_SUB is true because the dummy
        argument array ASARRAY is declared to be assumed-shape.  This means the
        interface for A_S_SUB must be explicit and it also means that a
        descriptor describing ARRAY will be passed as the actual argument to
        ASARRAY.  Since all the bound information is known about the array,
        it can be compared against the information in the descriptor
        describing pointer ASP.  In this case, the information matches, so
        ASSOCIATED returns true.  The second result of ASSOCIATED is also 
        true because PTR2 is accessible to A_S_SUB and contains the same 
        information as PTR1.  Upon return from A_S_SUB, both PTR1 and PTR2
        remain associated with ARRAY(2:10:2, :).

        The first result of ASSOCIATED in the first call to E_S_SUB is false
        because the storage for actual argument array ARRAY is not
        contiguous so there is no contiguous sequence association between
        ARRAY and ESARRAY.  Thus, a processor may copy the array
        section ARRAY(2:20:2, :) to a 5 by 10 element temporary array and
        pass that temporary array to ESARRAY.  Since pointer PTR1 is pointer
        associated with ARRAY and not with the temporary array, the first
        result of ASSOCIATED in E_S_SUB for this invocation is false.  The 
        same holds true for the second result of ASSOCIATED for the same 
        reason:  PTR2 is not associated with the temporary array.

        The result of ASSOCIATED (in both cases) in the second invocation of
        E_S_SUB is dependent on both the values of I, J, and K and the
        processor.  If the values of I, J, and K are such that they reference
        the whole of the first dimension and K has the value 1, then ARRAY is a
        candidate for being contiguously sequence associated with dummy
        argument ESARRAY.  It is then up to the processor whether or not it
        determines the values of I, J, and K at program execution time.  If
        it chooses to do so (or has the capability to do so), and finds that
        the reference may be contiguously sequence associated with ESARRAY,
        it can pass ARRAY directly rather than copying it to a temporary array.
        In this case, ASSOCIATED in this invocation of E_S_SUB will return
        true.  If, however, the processor does not choose to determine the
        values of I, J, and K at execution time, it can copy the array section
        to a temporary array and then pass that temporary array to ESARRAY.
        Since both PTR1 and PTR2 point at ARRAY rather than at the temporary
        array, neither dummy pointer argument ESP nor PTR2 are associated
        with the temporary array passed to dummy array argument ESARRAY so
        ASSOCIATED returns false in both cases.

        In the third case, the results of ASSOCIATED are dependent on what
        pointer, if any, is pointer associated with the target dummy argument
        within the called procedure.  Essentially, any pointer passed into
        the procedure is irrelevant because the actual array argument
        associated with the dummy array argument does not have the TARGET
        attribute therefore no pointer in the invoking procedure could be
        pointer associated with the actual array argument.

        The ASSOCIATED function will only return true if a pointer accessible
        to the called procedure is pointer associated with the target dummy
        argument during the execution of the procedure.  

        An example of this is:

              MODULE DEF
              REAL, POINTER :: PTR(:)
              END MODULE

              SUBROUTINE TEST (ARR)
              USE DEF
              REAL, POINTER :: Z(:)
              REAL, TARGET  :: ARR
              IF (ASSOCIATED(Z, ARR)) ...
              PTR => ARR
              ...                           ! Assume no changes to PTR.
              IF (ASSOCIATED(P, ARR)) ...
              END SUBROUTINE

        Since Z was not pointer associated with ARR prior to the first
        invocation of ASSOCIATED, the first invocation of ASSOCIATED returns
        false.  Since PTR is accessible to subroutine TEST via use association
        and since PTR was pointer associated with ARR prior to the second 
        invocation of ASSOCIATED, the second invocation of ASSOCIATED returns
        true.

        Upon completion of the execution of subroutine TEST, if Z and PTR 
        have not been nullified, they are left dangling in an undefined state.



------------------------------------------------------------------------------
Larry Rolison          lrr@cray.com
Cray Research, Inc.
655F Lone Oak Drive
Eagan, MN  55121
------------------------------------------------------------------------------
