From LJM@SLACVM.BITNET Wed Aug 24 02:58:00 1994
Received: from vm.uni-c.dk by dkuug.dk with SMTP id AA23147
  (5.65c8/IDA-1.4.4j for <SC22WG5@dkuug.dk>); Thu, 25 Aug 1994 03:48:00 +0200
Message-Id: <199408250148.AA23147@dkuug.dk>
Received: from vm.uni-c.dk by vm.uni-c.dk (IBM VM SMTP V2R2) with BSMTP id 8890;
   Thu, 25 Aug 94 03:33:53 DNT
Received: from SLACVM.SLAC.STANFORD.EDU by vm.uni-c.dk (Mailer R2.07) with
 BSMTP id 2813; Thu, 25 Aug 94 03:32:08 DNT
Received: by SLACVM (Mailer R2.08 R208004) id 2322;
          Wed, 24 Aug 94 18:00:06 PST
Date: Wed, 24 Aug 1994   10:58 -0800 (PST)
From: "Len Moss"                                     <LJM%SLACVM@vm.uni-c.dk>
To: "Jerry Wagener"                               <jwagener@amoco.com>
Cc: "SC22/WG5 Mailing List"                        <SC22WG5@dkuug.dk>
X-Charset: ASCII
X-Char-Esc: 29
Subject: Re: (SC22WG5.612) X3J3 letter ballot on enable

In-Reply-To: jwagener@amoco.com -- 08/20/94 05:15

Here is my complete response to the letter ballot on the ENABLE
proposal.  Please ignore my previous response which I accidentally
sent prematurely.

>======== X 3 J 3   L E T T E R   B A L L O T   ON   ENABLE ========
>(And see separate email note for additional background concerning this ballot.)
>
>Ballot period is 1 Sep 94 to 30 Sep 94.
>Send vote, by email and by 30 Sep 94, to Jerry Wagener, jwagener@amoco.com
>
>At X3J3 meeting 130 the enable proposal as represented in document 94-258r4
>was formally approved to replace the 94-009r2 entry for the ENABLE construct,
>with status "approved by X3J3, pending the results of a 30-day X3J3 letter
>ballot following the meeting".  This is that letter ballot.  The complete text
>of 94-258r4 is attached to this letter ballot.
>
>         __ approve meeting action on 94-258r4, without comments
>
>         __ approve meeting action on 94-258r4, with comments (attached)
>
>         __ disapprove meeting action on 94-258r4, with reasons (attached)
>

Again, I hope it's OK to vote early.

I vote NO on the Enable proposal, 94-258r4.  My principal reason for
voting NO is that I do not believe this proposal can be correctly
integrated into a complete standard within the time allotted for
producing Fortran 95.  Even a "good faith" attempt to do so is, in
my opinion, likely to consume too much of the committee's resources
and result in a substantial delay for the remainder of the Fortran
95 work.

In addition to this schedule concern, I have very serious objections
to the technical content of the proposal.

The restriction against transfers of control out of enable
constructs is too onerous and would make the facility unusable for
the average user.  Moreover, this restriction would encourage the
misuse of the facility in certain cases to simulate a transfer of
control.  Here is a modified version of Example B from the proposal
illustrating the kinds of abuses I have in mind:

   ! Example B-prime:
   !    This example is similar to Example B, but (mis)uses two
   !    additional conditions, ALLOCATION_ERROR and DEALLOCATION_ERROR,
   !    to simulate the effect of CYCLE and EXIT.  It is assumed that
   !    the fast algorithm does not make use of the ALLOCATE statement.
   ENABLE (OVERFLOW)
   ! First try a fast algorithm for inverting a matrix.
   : ! Code that cannot signal overflow
      ENABLE (DEALLOCATION_ERROR) ! Set up to simulate EXIT
         DO K = 1, N
            ENABLE (ALLOCATION_ERROR) ! Set up to simulate CYCLE
               :
               IF ... SIGNAL (ALLOCATION_ERROR,-1) ! Simulate CYCLE
               :
               IF ... SIGNAL (DEALLOCATION_ERROR,-1) ! Simulate Exit
               :
            HANDLE ! Receives control on simulated CYCLEs
            END ENABLE ! for simulated CYCLEs
         END DO
      HANDLE ! Receive control on simulated EXITs
      END ENABLE ! for simulated EXITs
      ENABLE
      :
      END ENABLE
   HANDLE
   ! Alternative code which knows that K-1 steps have executed normally.
   :
   END ENABLE

If necessary, the rules about which variables become undefined when a
condition is signalled will have to be broadened in the presence of
transfers of control (even conditional transfers) inside an enable
construct.

The lack of user-defined conditions is also unacceptable.  It will
inevitably lead to the misuse of intrinsic conditions.  Furthermore,
I no longer think that previous solutions to this problem, namely,
a single catch-all USER condition or global scope for all condition
names is acceptable.  User condition names should be declared and
should follow the same scoping rules as for variables.

The interaction of this proposal with the automatic deallocation
proposal is not spelled out and appears to be tricky: the latter
eliminates the allocation status of "undefined", but this appears
to be what is required if an ALLOCATE statement occurs somewhere in
the innermost ENABLE block when a condition is signalled.

This proposal give no guidance to an IEEE implementer as to whether
an ENABLE statement is an appropriate vehicle to control whether
numeric exceptions signal or propagate.  At first glance, it would
seem to be a good choice, but I suspect there are a variety of
pitfalls to such an approach.  There should be some discussion of
this issue in a footnote.

In the past, we have always interpreted a program that violates an
absolute prohibition in the text as non-conforming and permitted the
processor to deal with such programs any way it sees fit; the
exception handling facility would limit the freedom of the processor
to deal with many violations of the existing rules, but the edits in
this proposal do not reflect this.  Here are just a few examples of
conditions and conflicting absolute prohibitions:

   BOUND_ERROR
     64/31, "The value of a subscript in an array element must be
       within the bounds for that dimension."
     65/33-34, "Each subscript [in a sequence of subscripts
       by an array section] must be within the bounds for its
       dimension unless the sequence is empty."

   SHAPE
     90/5, "For an intrinsic assignment statement, <variable> and
       <expr> must conform in shape..."

   MANY_ONE
     89/31, "The <variable> [in an array assignment statement] must
       not be a many-one array section."

   PRESENT
     179/31, "A dummy argument that is not optional must be
       present."

   UNDEFINED
     61/4, "A reference is permitted only if the data object is
       defined."

>
>============ t e x t    o f    94-258r4    f o l l o w s ==============
>
>To: X3J3                                                         X3J3/94-258r4
>From: John Reid
>Subject: Enable proposal
>Date: 19 August 1994
>
>
>
>1. RATIONALE
>
>If an operator invokes a process (for example, in hardware or in a procedure
>for a defined operator) and hits a problem with which it cannot deal, such as
>overflow, it needs to quit and ask the caller to do something else.  A simple
>example of this proposal is
>
>   ENABLE (OVERFLOW)
>      :
>      ... = X*Y ...
>   HANDLE
>      :
>   END ENABLE
>
>If the multiply is intrinsic and an overflow occurs, a transfer of control is
>made to the block of code following the HANDLE statement.  Similarly, if the
>multiply is a defined operator, it can be arranged that the OVERFLOW signals
>in comparable circumstances.  The handle block may contain very carefully
>written code that is slow to execute but circumvents the problem, or may
>arrange for a graceful termination.
>
>2. TECHNICAL SPECIFICATION
>
>For dealing with exceptional events, this proposal involves the addition of
>integer-valued intrinsic conditions, a new construct, and some new statements.
>The intrinsic values are all positive, but negative values may be set by
>execution of a SIGNAL statement.  For the definition of the conditions, see
>the proposed new section 15 at the end of this paper.  Also, there are more
>examples in the proposed new sub-section 8.1.5.5.
>
>The enable construct has the general form
>         enable statement
>              [enable block]
>         [handle statement
>              handle block]
>         end enable statement
>Nesting of enable constructs is permitted.  An enable or handle block may
>itself contain an enable-construct.  Also, nesting with other constructs is
>permitted, subject to the usual rules for proper nesting of constructs.
>
>The enable statement lists the names of the conditions to be signaled.  If any
>of these conditions signals during the execution of the enable block, control
>is transferred to the handle block.  A simple example is the following:
>   ! Example A
>   ENABLE (OVERFLOW)
>    ! First try a fast algorithm for inverting a matrix.
>      :
>   HANDLE
>    ! Fast algorithm failed; use slow one.
>      :
>   END ENABLE
>Here, the code in the enable block takes no precautions against overflow and
>will usually execute correctly.  Should it fail with overflow, the alternative
>algorithm is used instead.
>
>The transfer to the handle block is imprecise in order to allow for
>optimizations such as vectorization.  Any variable that is defined or
>redefined in a statement of the enable block becomes undefined.  In Example A,
>a copy of the matrix itself would need to be available for the slow algorithm.
>
>The transfer may be made more precise by adding within the enable block a
>nested enable construct without a handler.  If any of the conditions is
>signaling when the inner enable statement is executed, control is transferred
>to the handle block.  This reduces the imprecision to either the statements
>within the inner construct or those outside the inner construct.  Adding such
>a construct to the code of Example A gives:
>
>   ! Example B
>   ENABLE (OVERFLOW)
>   ! First try a fast algorithm for inverting a matrix.
>   : ! Code that cannot signal overflow
>      DO K = 1, N
>         ENABLE
>         :
>         END ENABLE
>      END DO
>      ENABLE
>      :
>      END ENABLE
>   HANDLE
>   ! Alternative code which knows that K-1 steps have executed normally.
>   :
>   END ENABLE
>Note that the enable, handle, and end-enable statements provide effective
>barriers to code migration by an optimizing compiler.
>
>If there is no handler for a signaling condition (for example, if a condition
>signals outside any enable construct for the condition), a transfer of control
>as for a return statement takes place in a procedure or as for a stop
>statement takes place in a main program.  The condition continues to signal.
>
>When an enable statement is encountered, if any conditions that are enabled or
>are about to be enabled are signaling, a transfer of control to the next outer
>handler for a signaling condition (or a return or stop) takes place.  This
>ensures that all enabled conditions are quiet on entering the enable block.
>Upon normal completion of the handle block, any of the handled conditions that
>is signaling is reset to quiet.
>
>There is an option on the enable statement to specify that some of the
>conditions enabled are 'immediate'.  Any <executable-construct> of the enable
>block that might signal one of the immediate conditions is treated as if it
>were followed by an enable construct with an empty body and no handler.  An
>example of such an enable statement is
>      ENABLE, IMMEDIATE (OVERFLOW)
>
>For some conditions (mainly those that may require additional object code, for
>example, BOUND_ERROR), the processor is required to signal the condition only
>within the statements of the enable block.  Whether such a condition signals
>outside any enable block for the condition is processor dependent.  There is
>no requirement to signal such a condition in a procedure that is called from
>within an enable block.
>
>There is an option on the handle statement to specify the handling of further
>conditions.  For example,
>    HANDLE (ALL_CONDITIONS)
>specifies that any condition that signals during the execution of the enable
>block be handled, including those that the processor handles outside enable
>blocks.  These conditions, as well as those enabled, cause a transfer of
>control to an outer handler if they are signaling when an enable statement is
>encountered.
>
>There is a facility for making a specified condition signal with a specified
>value.  This is done with the SIGNAL statement.  An example is
>      SIGNAL(OVERFLOW, -3)
>               ! Negative values of intrinsic conditions can be set this way.
>It causes a transfer to the handler if in an enable block that has a handler
>for the condition; otherwise, it causes a return in a subprogram or a stop in
>a main program.  This may also be used to set conditions quiet.  For example,
>   SIGNAL(ALL_CONDITIONS, 0)
>sets all conditions quiet. In this case, there is no transfer of control.
>
>In a handler, if it is desired to resignal the signaling conditions, this can
>be achieved with the pair of statements
>   ENABLE
>   END ENABLE

Adding a special statement to resignal conditions inside a handler
my be redundant with an empty ENABLE/END ENABLE block, but it is far
more intuitive.  See my comments below regarding empty enable blocks
outside of handlers.

>A transfer of control to the next outer handler for a signaling condition (or
>a return or stop) occurs without the values of the conditions changing.

In a handler, is it possible to first set some conditions quiet, then
resignal any conditions that are still signalling?  If so, what happens
if a condition is raised _within_ such a handler -- does the set of
signalling conditions itself become imprecise?  Note that it is not
possible to avoid such imprecision by nesting additional enable blocks
since the first ENABLE encountered inside the handler causes the
resignal.

>
>There is a facility for finding the value of a condition.  This is done with
>the CONDITION_INQUIRE statement.  An example is
>   CONDITION_INQUIRE(OVERFLOW, I)
>which stores the value of the overflow condition in the variable I.  Another
>form of the statement:
>   CONDITION_INQUIRE(CHAR_ARRAY)
>returns the names of the conditions that are signaling in the character array
>variable CHAR_ARRAY.
>
>Each condition has a default integer value.  The scoping rules for intrinsic
>conditions are as for intrinsic procedures.  A future enhancement might allow
>the declaration of user conditions with scoping rules similar to those for
>variables.

(See my objections above to postponing the addition of user conditions to a
future standard.)

>
>If a condition is still signaling when the program stops, the processor must
>issue a warning on the default output unit.

The warning should be required to include a list of all signalling
conditions at termination time and their associated integer values.

>
>Neither a handle statement nor an end-enable statement is permitted to be a
>branch target.  A handle-block is intended for execution only following the
>signaling of a condition that it handles, and an end-enable statement is not a
>sensible target because it would permit skipping the handling of a condition.
>
>Branching out of an enable construct is not permitted.  This limits the extent
>of uncertainty over which statements have been executed when a handler is
>entered.

(See my objections above to this restriction.)

>
>
>3. EDITS TO THE STANDARD
>
>6/18+. Add
>      IEC 559:1989, <Binary floating-point arithmetic for microprocessor
>      systems>
>      (also ANSI/IEEE 754-1985, IEEE standard for binary floating-point
>      arithmetic).
>.......................................................................
>
>8/45+. Add
>              <<or>>  <enable-construct>
>.......................................................................
>
>9/4-24. Add to R216 (in alphabetic positions) the lines
>              <<or>>  <condition-inquire-stmt>
>              <<or>>  <signal-stmt>
>.......................................................................
>
>12/50. After 'CASE constructs,', add 'ENABLE constructs,'.
>.......................................................................
>
>12/53+. Add:
>     (4) Execution of a signal statement (8.1.5.4) may change the execution
>         sequence.
>     (5) Execution of an enable statement (8.1.5.1) may change the execution
>         sequence.
>.......................................................................
>
>15/33+ Add
>
><<2.4.8 Condition>>
>
>A <<condition>> is a default integer flag associated with the occurrence of an
>exceptional event.  The value 0 corresponds to the quiet state and this is its
>initial value.  Processor dependent nonzero values correspond to signaling
>states.  Negative values can occur only through execution of the SIGNAL
>statement.  The value may be found by execution of a CONDITION_INQUIRE
>statement.
>
>[Footnote: The reason for specifying that conditions have integer values is
>that this leaves open the possibility of providing detailed information about
>the condition.  This will be useful when a procedure (for example, in a
>library) signals a condition so that it can indicate the cause of the problem.
>The intrinsic values are forced to be positive so that a negative value can be
>seen to be created by source code and not by the system.]
>
>[Footnote: Although multitasking is not part of Fortran 90, the interaction of
>this proposal with multitasking extensions has been considered.  A model is
>that each virtual processor has a flag for each condition.  For example,
>condition handling is permissible within a pure procedure.  Enable, handle,
>and end-enable statements act as barriers at which the condition values are
>merged.]

I don't understand this -- does it mean that an enable statement
_inside_ a PURE procedure forces a merge of condition values across
all concurrently executing instances of the procedure? I suspect
not, but I don't see anything in the edits below that spells out
exactly what it does mean.

>.....................................................................
>
>22/23+ Add to the Blanks Optional column:
>            END ENABLE
>.......................................................................
>
>67/39.  After 'terminated', add 'unless the ALLOCATION_ERROR condition is
>        enabled'.
>.......................................................................
>
>68/40.  After 'terminated', add 'unless the DEALLOCATION_ERROR condition is
>        enabled'.
>.......................................................................
>
>80/2.  After 'program', add ', except in an enable block for a suitable
>       condition'.
>.......................................................................
>
>95/10+ Add
>
>         (4) ENABLE construct

The statement at 95/18, "Execution of such a block [i.e., an empty
block] has no effect." needs at least a footnote distinguishing
_entry_ into an empty enable block, which can indeed have an effect,
from execution of the (null) block itself.

>.......................................................................
>
>95/19. Delete 'three'.
>........................................................................
>

If the restriction against transfers of control out of an enable
construct is retained, section 8.1.1.2 [95/33-37], "Control flow in
blocks" needs to be rewritten.

>107/0+. Add
>
><<8.1.5 Condition handling>>
>
>A condition has a name with the same scoping rules as for intrinsic procedures
>and a value of type default integer.  The value zero corresponds to the normal
>or 'quiet' state and nonzero values correspond to exceptional circumstances.
>All conditions have initial value zero.  The processor is required to signal a
>condition if the associated circumstance occurs during execution of an
>intrinsic operation or an intrinsic procedure call specified in the scope of
>an enable block for the condition.  Some conditions are also required to
>signal when the circumstance occurs outside an enable block, but whether other
>conditions signal outside an enable block is processor dependent.  For the
>detailed specification, see Section 15.  When the processor signals a
>condition, it has a positive value.  The SIGNAL statement (8.1.5.4) may be
>used to give it a negative value.
>
>[Footnote: For a condition whose signaling outside enable blocks is processor
>dependent, the control of whether the condition so signals is also processor
>dependent.  There might be an option on the command line or there might be an
>intrinsic procedure that provides dynamic control.  It is expected that by
>default the conditions UNDERFLOW and INEXACT will not signal except inside
>enable blocks.]
>
>[Footnote: The proposal allows the in-lining of procedures with no change to
>the enable constructs.  On some processors, this may cause a condition that
>does not signal outside enable blocks to signal.]
>
>[Footnote: On many processors, it is expected that some conditions will cause
>no alteration to the flow of control when they signal and that they will be
>tested only when the enable block completes or another enable statement is
>encountered.  Thus the overheads of testing the condition are confined
>precisely to the places where the programmer has requested a test.  On other
>processors, this may be very expensive.  They may instead cause a transfer of
>control to the handler (or a return or stop) as soon as the condition signals
>or soon thereafter.]
>
>[Footnote: If additional code is needed (for example, to diagnose integer
>overflow), this is required only within the scope of the enable block.]
>
>In a sequence of statements that contains no condition handling statements, if
>the execution of a process would cause a condition to signal but after
>execution of the sequence no value of a variable depends on the process,
>whether the condition signals is processor dependent.  For example, when Y has
>the value zero, whether the code
>           X = 1.0/Y
>           X = 3.0
>signals DIVIDE_BY_ZERO is processor dependent.
>
>A condition must not signal if the signal could arise only during execution of
>a process not required by the standard.  For example, the intrinsic LOG in the
>statement
>           IF (F(X)>0.) Y = LOG(Z)
>must not signal a condition when both F(X) and Z are negative and for the
>statement
>           WHERE(A>0.) A = LOG (A)
>negative elements of A must not cause signaling.
>
>[Footnote: In general, it is intended that implementations be free within
>enable constructs to use the code motion techniques that they use outside
>enable constructs.]
>
><<8.1.5.1. The enable construct>>
>
>The ENABLE construct specifies a (possibly empty) set of conditions, an enable
>block, and (optionally) a handle block with (optionally) a further set of
>conditions.  The handle block is executed only if execution of the enable
>block leads to the signaling of one or more of the conditions.
>
>R835a <enable-construct>    <<is>> <enable-stmt>
>                                     [<enable-block>]
>                                  [<handle-stmt>
>                                      <handle-block>]
>                                   <end-enable-stmt>
>
>R835b <enable-stmt>         <<is>> [<enable-construct-name>:]         #
>                                   # ENABLE [(<condition-name-list>)]   #
>                                   # [,IMMEDIATE (<condition-name-list>)]
>
>R835c <enable-block>        <<is>> <block>
>
>R835d <handle-stmt>         <<is>> HANDLE [(<condition-name-list>)] #
>                                   #  [<enable-construct-name>]
>
>R835e <handle-block>        <<is>> <block>
>
>R835f <end-enable-stmt>     <<is>> END ENABLE [<enable-construct-name>]
>
>Constraint: If the <enable-stmt> of an <enable-construct> is identified
>            by an <enable-construct-name>, the corresponding
>            <end-enable-stmt> must specify the same
>            <enable-construct-name>. If the <enable-stmt> of an
>            <enable-construct> is not identified by an
>            <enable-construct-name>, the corresponding
>            <end-enable-stmt> must not specify an
>            <enable-construct-name>. If the <handle-stmt> is identified
>            by an <enable-construct-name>, the corresponding
>            <enable-stmt> must specify the same <enable-construct-name>.
>
>Constraint: A condition name must not appear more than once in an
>            <enable-stmt>.
>
>Constraint: A condition name must not appear more than once in a
>            <handle-stmt>.
>
>The conditions named on the enable statement are enabled during execution of
>the enable block.  The set of conditions handled by the handle block consists
>of all those named on the enable statement or on the handle statement.  If the
>enable construct is nested within an enable block, the conditions enabled for
>the outer block are also enabled for the inner block.
>
>An <enable-stmt> may be a branch target statement (8.2).
>
>[Footnote: Neither a handle statement nor an end-enable statement is permitted
>to be a branch target.  A handle-block is intended for execution only
>following the signaling of a condition that it handles, and an end-enable
>statement is not a sensible target because it would permit skipping the
>handling of a condition.]
>
>[Footnote: Nesting of enable constructs is permitted.  An enable or handle
>block may itself contain an enable-construct.  Also, nesting with other
>constructs is permitted, subject to the usual rules for proper nesting of
>constructs.]
>
>Execution of an enable statement causes a transfer of control if a signaling
>condition is handled by the enable construct or any enable construct within
>which it is nested.  If the enable statement is nested in an enable block that
>has a handler for a signaling condition, the transfer is to the handler of the
>innermost such enable block.  Otherwise, it is as for a return if in a
>subprogram, or a stop if in a main program.  The values of the conditions are
>not altered.
>
>[Footnote: In an enable block, the pair of statements
>       ENABLE
>       END ENABLE
>has a checking effect.  If any handled condition is signaling, there will be a
>transfer of control to an outer handler (or a stop or return).The values of
>the conditions are not altered.]
>
>[Footnote: Note that in a function subprogram it is very desirable to ensure
>that the function value is defined even if an error condition has been
>diagnosed and is expected to be handled in the calling subprogram.  If the
>function value is not defined, further conditions will probably be signaled
>during the evaluation of the expression that gave rise to the function call,
>which may mask the condition that was the root cause.]
>
>[Footnote: If a condition handled by a handler signals again during execution
>of the handler, this second signal will be indistinguishable from the first.
>If it is desired to handle it separately, it must be set to the quiet value
>and a nested enable must be provided.]
>
>The value of each condition handled by the enable construct is set to the
>quiet value upon completion of execution of the <handle-block>.
>
><<8.1.5.2 Execution of an enable construct>>
>
>Execution of an <enable-construct> begins with the first executable construct
>of the <enable- block>, and continues to the end of the block unless a handled
>condition is signaled.  If a condition handled by the <enable-construct>
>signals outside any enable construct that handles the condition and is nested
>within the enable block, control is transferred to the <handle-block>.
>Transfer of control to the <handle-block> may take place on completion of
>execution of the enable-block or may take place sooner after the signaling of
>the condition.  Any variable that might be defined or redefined by execution
>of a statement of the enable block outside any enable construct that handles
>the condition and is nested within the enable block is undefined, any pointer
>whose pointer association might be altered has undefined pointer association
>status, any allocatable array that might be allocated or deallocated may have
>been allocated or become unallocated, and the file position of any file
>specified in an input/output statement that might be executed is processor
>dependent.
>
>[Footnote: The transfer to the handle block is imprecise in order to allow for
>optimizations such as vectorization.  As a consequence, some variables become
>undefined.  In Example 3 of 8.1.5.6, a copy of the matrix itself would need to
>be available for the slow algorithm.]
>
>Branching out of an enable construct is not permitted.  A CYCLE or EXIT
>statement is not permitted in an enable construct unless the do construct to
>which it belongs is nested within the enable construct.  An alternate return
>specifier in an enable construct must not specify the label of a statement
>outside the construct.  An ERR=, END=, or EOR= specifier in a statement in an
>enable construct must not be the label of a statement outside the construct.
>A RETURN or STOP statement is permitted in an enable construct.  Conditions
>retain their values on execution of a RETURN or STOP statement.
>
>[Footnote: The ban on branching out of an enable construct limits the extent
>of uncertainty over which statements have been executed when a handler is
>entered.]

(See my objections above to this restriction.)

>
>Any <executable-construct> of the enable block that might signal one or more
>of the conditions in the immediate list on the enable statement is treated as
>if it were followed by an <enable-construct> with an empty enable block and no
>handler.

If a condition in the immediate list is signalled while evaluating the
<scalar-logical-expr> part of an IF statement, must the transfer of
control occur before execution of the <action-stmt> part of the IF
statement?

>
>Execution of the <handle-block> completes the execution of the
><enable-construct>.
>
>If no condition handled by the enable construct is signaling on completion of
>execution of the <enable-block>, the execution of the entire construct is
>complete.
>
>[Footnote: Nested enable constructs without handlers can be employed to reduce
>the imprecision of an interrupt.  Note that enable, handle, and end-enable
>statements provide effective barriers to code migration by an optimizing
>compiler.]

Enable constructs themselves must be properly nested; however, empty
enable blocks can be freely scattered amongst other types of blocks
to act as exception-handling barriers without requiring any special
nesting; for example,

      :
      ENABLE;END ENABLE
      DO ...
         :
         ENABLE; END ENABLE
         IF...THEN
            :
            ENABLE; END ENABLE
         ELSE
            :
            ENABLE; END ENABLE
         END IF
         :
         ENABLE; END ENABLE
      END DO

This is fairly ugly and should be replaced with a single statement
that would have the same effect (and which could also be used to
resignal conditions within a handler -- see my comments above).
I suggest something like 'SIGNAL *'.

>
><<8.1.5.3 Signaling conditions that are not enabled>>
>
>A processor may signal a condition while executing a statement that is not in
>an enable block for the condition.  If in a subprogram, a return is executed
>without alteration of the values of the conditions.  If in a main program, a
>stop is executed and the processor must issue a warning on the default output
>unit.

As noted above, there should be a requirement that the warning
indicate which conditions are signalling and what the associated
integer values are.

>
>[Footnote: On return to the caller, the condition will be signaling.  If the
>invocation is within an enable block that has a handler for the condition,
>there will be a transfer to the handler (or a return or stop), but not
>necessarily until the execution of the block is complete.  If the invocation
>is not within an enable block that has a handler for the condition, there may
>be a return (or stop) at once, or the processor may continue executing.]
>
>
><<8.1.5.4 Signal statement>>
>
>R835g  <signal-stmt> <<is>> SIGNAL (<condition-name>,<scalar-int-expr>)
>
>Constraint: The <scalar-int-expr> must be of type default integer.
>
>Constraint: If the condition name is that of a combination condition (15.7),
>the <scalar-int- expr> must be the literal constant 0.

Why must a literal 0 be used to set combination conditions quiet?  A
symbolic constant (e.g., "QUIET") or even an initialization
expression with a value of zero would seem to work equally well and
be more regular.

>
>The SIGNAL statement changes the value of the condition it names to that of
>the expression it contains.  If the value is nonzero, it causes a transfer of
>control.  If the statement is in an enable block of an enable construct that
>has a handler for the condition, the transfer is to the handler of the
>innermost such enable construct.  Otherwise, it is as for a return if in a
>subprogram, or a stop if in a main program.
>
>[Footnote: In a handler, the pair of statements
>       ENABLE
>       END ENABLE
>has a resignaling effect.  If any handled condition is signaling, there will
>be a transfer of control to an outer handler (or a stop or return).The values
>of the conditions are not altered.]

(See my comments above about resignaling and empty enable blocks.)

>
>
><<8.1.5.5 Examples of ENABLE constructs>>
>
>Example 1:
>
>   MODULE MATRIX
>! Module for matrix multiplication of real arrays of rank 2.
>      INTERFACE OPERATOR(.mul.)
>         MODULE PROCEDURE MULT
>      END INTERFACE
>   CONTAINS
>      FUNCTION MULT(A,B)
>         REAL, INTENT(IN) :: A(:,:),B(:,:)
>         REAL MULT(SIZE(A,1),SIZE(B,2)
>         ENABLE (INTRINSIC, OVERFLOW)
>            MULT = MATMUL(A, B)
>         HANDLE
>            SIGNAL(INEXACT, -1)
>         END ENABLE
>      END FUNCTION MULT
>   END MODULE MATRIX
>
>This module provides matrix multiplication for real arrays of rank 2.  Since
>the condition INSUFFICIENT_STORAGE signals outside enable blocks (see Section
>15.1), if there is insufficient storage for the necessary temporary array, the
>module will signal the condition INSUFFICIENT_STORAGE.  If an INTRINSIC or

Modules themselves can't signal; "module" in the above line should
be changed to "module procedure".

>OVERFLOW condition occurs, the module will signal the condition INEXACT with
>value -1.
>
>
>Example 2:
>
>IO_CHECK: ENABLE (IO_ERROR, END_OF_FILE)
>             :
>             READ (*, '(I5)') I
>             READ (*, '(I5)', END = 90) J
>             :
>       90    J = 0
>          HANDLE
>             CONDITION_INQUIRE(END_OF_FILE,K)
>             IF (K/=0) THEN
>                WRITE (*, *) 'Unexpected END-OF-FILE when reading ', &
>                             'the real data for a finite element'
>             ELSE
>                CONDITION_INQUIRE(IO_ERROR,K)
>                IF (K /= 0) WRITE (*, *) 'I/O error when reading ', &
>                             'the real data for a finite element'
>             END IF
>             STOP
>          END ENABLE IO_CHECK
>
>In this example, if an input/output error occurs in either of the READ
>statements or if an end- of-file is encountered in the first READ statement,
>the appropriate condition will be signaled and the handler will receive
>control, print a message, and terminate the program.  However, if an
>end-of-file is encountered in the second READ statement, no condition will be
>signaled and control will be transferred to the statement indicated in the
>END= specifier.
>
>
>Example 3:
>
>   ENABLE (USUAL)
>    ! First try the "fast" algorithm for inverting a matrix:
>      MATRIX1 = FAST_INV (MATRIX)
>                        ! MATRIX is not altered during execution of FAST_INV.
>   HANDLE
>    ! "Fast" algorithm failed; try "slow" one:
>      SIGNAL (USUAL, 0)
>      ENABLE (USUAL)
>         MATRIX1 = SLOW_INV (MATRIX)
>      HANDLE
>         WRITE (*, *) 'Cannot invert matrix'
>         STOP
>      END ENABLE
>   END ENABLE
>
>In this example, the function FAST_INV may cause a condition to signal.  If it
>does, another try is made with SLOW_INV.  If this still fails, a message is
>printed and the program stops.  Note the use of nested enable constructs.
>Note, also, that it is important to set the signals to 'quiet' before the
>inner enable.  If this is not done, a condition will still be signaling when
>the inner ENABLE is encountered, which will cause an immediate transfer to an
>outer handler (or a stop or return).
>
>
>Example 4:
>
>   ENABLE (OVERFLOW)
>   ! First try a fast algorithm for inverting a matrix.
>   : ! Code that cannot signal overflow
>   DO K = 1, N
>      ENABLE
>      :
>      END ENABLE
>   END DO
>      ENABLE
>      :
>      END ENABLE
>   HANDLE
>   ! Alternative code which knows that K-1 steps have executed normally.
>   :
>   END ENABLE
>
>Here the code for matrix inversion is in line and the transfer is made more
>precise by adding to the enable block two enable constructs without handlers.
>
>
>Example 5:
>
>The following subroutine finds a zero of <f(x)> on an interval [<a,b>].  It is
>limited to take one second of real time as measured by the system clock.  If
>it fails to obtain the requested accuracy after this time, the condition
>INEXACT signals with the value -1.
>
>   SUBROUTINE ZERO_SOLVER (A, B, X, TOLERANCE, F)
>      REAL A, B, X, TOLERANCE
>      INTERFACE; REAL FUNCTION F(X); REAL X; END INTERFACE
>
>      INTEGER  COUNT, RATE, START ! Local variables
>      CALL SYSTEM_CLOCK(START, RATE)
>      :
>   ! The following code is executed every iteration
>      CALL SYSTEM_CLOCK(COUNT)
>   ! If time has run out, return, signaling condition INEXACT.
>      IF (COUNT > START+RATE) SIGNAL (INEXACT,-1)
>      :
>   END SUBROUTINE ZERO_SOLVER
>
>
>
>The application code handles the exception in a way that only it knows.  An
>example is:
>
>   :
>   ENABLE
>       CALL ZERO_SOLVER (A, B, X, TOLERANCE, F)
>   HANDLE (INEXACT)
>
>   ! Exceeded time limit. Fix up and go on.
>      :
>   END ENABLE
>   :
>

This example illustrates my point about the need for user-defined
condition names.  INEXACT is not really an appropriate condition
name for a time-out situation, and is a particularly poor choice
for this example, since there is a very real likelihood that the
function F could, on an IEEE machine, itself raise the INEXACT
condition.

>
>
>Example 6:
>
>      REAL FUNCTION CABS (Z)
>        COMPLEX Z
>! Calculate the complex absolute value, using a scaled algorithm
>!   if  the straightforward calculation underflows or overflows. Set the
>!   overflow condition to the value -1 if the result is too large to
>!   be representable.
>
>        REAL S, ZI, ZR
>        INTRINSIC REAL, AIMAG, SQRT, ABS, MAX
>
>        ZR = REAL(Z)
>        ZI = AIMAG(Z)
>
>quick: ENABLE(OVERFLOW, UNDERFLOW)
>
>!         This is the quick and usual calculation.
>          CABS = SQRT(ZR**2 + ZI**2)
>
>        HANDLE quick
>
>!         Will try again using a scaled equivalent method.
>          S = MAX(ABS(ZR),ABS(ZI))
>          SIGNAL (OVERFLOW,0) ; SIGNAL (UNDERFLOW,0)
>  slow: ENABLE(OVERFLOW, UNDERFLOW)
>            CABS = S*SQRT( (ZR/S)**2 + (ZI/S)**2 )
>          HANDLE slow
>            CONDITION_INQUIRE(OVERFLOW,K)
>            IF (K/= 0) THEN
>!             The result is too large to be representable.
>              SIGNAL(OVERFLOW, -1)
>            ELSE
>              CONDITION_INQUIRE(UNDERFLOW,K)
>              IF (K/= 0)  CABS = S
>            END IF
>          END ENABLE slow
>
>        END ENABLE quick
>
>      END FUNCTION CABS
>
>This illustrates the setting of a special condition value when the problem
>really has a result that overflows.
>
>
>Example 7:
>
>      MODULE LIBRARY
>      ...
>      CONTAINS
>         SUBROUTINE B
>            ...
>            X = Y*Z(I) ! No condition enabled.
>            IF(X>10.)SIGNAL(OVERFLOW, 1)
>            ...
>         END SUBROUTINE B
>      END MODULE LIBRARY
>
>      SUBROUTINE A
>         USE LIBRARY
>         ENABLE
>            CALL B
>         HANDLE (OVERFLOW)
>            ...
>         END ENABLE
>      END SUBROUTINE A
>
>This illustrates the use of a library module that may signal the condition
>OVERFLOW.  The signal statement causes a transfer to the handler in the
>calling subroutine A.
>
>This also illustrates the effect of an intrinsic condition that is not
>enabled.  An overflow in Y*Z(I) would cause OVERFLOW to signal and hence a
>transfer to the handler in the calling subroutine A.  ...

I thought whether or not such a transfer occurred was
processor-dependent.

>                                                 ...  An out-of-range
>subscript value I might or might not signal BOUND_ERROR, but it would not be
>handled by subroutine A.
>
>
>Example 8:
>
>   ENABLE, IMMEDIATE (OVERFLOW)
>          A = B*C
>          WHERE(RAINING)
>               X(:) = X(:)*A
>          ELSEWHERE
>               Y(:) = Y(:)*A
>          END WHERE
>    HANDLE
>       .....
>    END ENABLE
>
>This illustrates the use of IMMEDIATE. The enable construct is equivalent to
>
>      ENABLE (OVERFLOW)
>          A = B*C
>          ENABLE
>          END ENABLE
>          WHERE(RAINING)
>               X(:) = X(:)*A
>          ELSEWHERE
>               Y(:) = Y(:)*A
>          END WHERE
>          ENABLE
>          END ENABLE
>    HANDLE
>       .....
>    END ENABLE
>
>Note that the statements of a WHERE construct are not tested separately.

What?!  The statements of a WHERE construct are executed in sequence so
they should be tested separately.  The equivalent construct should be:

      ENABLE (OVERFLOW)
          A = B*C
          ENABLE
          END ENABLE
          WHERE(RAINING)
               X(:) = X(:)*A
               ENABLE
               END ENABLE
          ELSEWHERE
               Y(:) = Y(:)*A
               ENABLE
               END ENABLE
          END WHERE
          ENABLE
          END ENABLE
    HANDLE
       .....
    END ENABLE

Moreover, if there were multiple assignments within one of the WHERE
blocks (at least, multiple assignments that could conceivably cause
an overflow), each such assignment should, in the equivalent
construct, be followed by an ENABLE/END ENABLE pair.

>
>Example 9:
>
>   SUBROUTINE LONG
>      REAL, ALLOCATABLE A(:), B(:,:)
>      : ! Other specifications
>      ENABLE
>          :
>          ! Lots of code, including many procedure calls
>          :
>      HANDLE (ALL_CONDITIONS)
>          ! Fix-up, including deallocation of any allocated arrays
>          IF(ALLOCATED(A)) DEALLOCATE (A)
>          IF(ALLOCATED(B)) DEALLOCATE (B)
>          :
>      END ENABLE
>   END SUBROUTINE LONG
>
>This illustrates the use of a handle statement with additional conditions.
>Here the enable block enables no conditions because fast execution is desired,
>but if anything goes wrong (for example, in one of the procedure invoked),
>fix-ups are performed, including deallocation of any local allocated arrays.
>
>......................................................................
>
>107/5. After '<end-do-stmt,>' add 'an <enable-stmt>,'.
>.......................................................................
>
>122/17-18. Replace sentence by
>   If an error condition (9.4.3) occurs during execution of an input/output
>   statement that lies in an enable block for the IO_ERROR condition or
>   contains an ERR= specifier:

Poor wording -- it sounds like the enable block contains an ERR= specifier.

>.......................................................................
>
>122/25. After 'continues with' add 'the handle block or'

This text does not spell out whether the ERR= statement or the handler
takes precedence when both are present.

>.......................................................................
>
>122/27-28. Replace sentence by
>   If an end-of-file condition (9.4.3) occurs and no error condition (9.4.3)
>   occurs during execution of an input/output statement that lies in an enable
>   block for the END_OF_FILE condition or contains an  END= specifier.
>.......................................................................
>
>122/34. After 'continues with' add 'the handle block or'

This text does not spell out whether the END= statement or the handler
takes precedence when both are present.

>.......................................................................
>
>122/37-38. Replace sentence by
>
>If an end-of-record condition (9.4.3) occurs and no error condition (9.4.3)
>occurs during condition of an input/output statement that lies in an enable
>block for the END_OF_RECORD condition or contains an EOR= specifier:
> ..................................................................
>
>123/6. After 'continues with' add 'the handle block or'

This text does not spell out whether the EOR= statement or the handler
takes precedence when both are present.

>........................................................................
>
>125/10. Before 'contains' add 'is not in a enable block for the IO_ERROR
>        condition and '.
>........................................................................
>
>125/11.  Before 'contains' add 'is not in a enable block for the END_OF_FILE
>         condition and '.
>........................................................................
>
>125/13.  Before 'contains' add 'is not in a enable block for the END_OF_RECORD
>         condition and '.
>........................................................................
>
>241/25. After 'procedures,' add 'intrinsic conditions,'.
>........................................................................
>
>241/35. After 'procedure,' add 'or condition'.
>........................................................................
>
>
><<15. CONDITIONS>>
>
>In this section, the conditions supported by the standard and a statement for
>obtaining the value of a condition are specified.
>
>The CONDITION_INQUIRE statement returns the value of a condition.
>
>R835i <condition-inquire-stmt> <<is>> CONDITION_INQUIRE (<condition-name>, #
>                                     # [STAT=]<scalar-default-int-variable>)
>                               <<or>> CONDITION_INQUIRE (<conditions-array>)
>
>835j <conditions-array>          <<is>> <default-char-variable>
>
>Constraint: The condition name must not be that of a combination condition
>(Section 15.7).
>
>Constraint: The <conditions-array> must be a rank-one array that is not of
>assumed size.
>
>The STAT= variable is defined with the value 0 if the condition named is quiet
>and a nonzero value otherwise.  Negative values can occur only following
>execution of a SIGNAL statement.
>
>The <conditions-array> is defined with the names of signaling conditions and
>blanks according to the rules of default assignment.  If there are <s>
>conditions signaling, the first <s> elements are defined with the names of
>these conditions and the remaining elements are given the value blank.  If the
>processor provides additional conditions, the names of the conditions defined
>by the standard must precede the names of any such additional intrinsics.  If
>there are more signaling conditions than the size of the array, all elements
>are defined with condition names and which are chosen is processor dependent.
>
>[Footnote: An array size 20 will always be adequate to return the names of all
>the conditions defined by the standard.  If the final element of the character
>array has the value blank, the names of all signaling conditions will have
>been returned.  If it is not blank, the user may set the conditions named
>quiet with SIGNAL statements and call CONDITION_INQUIRE again.]

How?  The returned condition names are character values, but the
SIGNAL statement requires a <name> in the BNF sense, not a character
value.  One could write a big SELECT to handle the standard
intrinsic conditions, but there's no portable way to handle
conditions added by the implementation.

>
>
><<15.1 Storage and addressing conditions>>
>
>ALLOCATION_ERROR
>This occurs when the processor is unable to perform an allocation requested by
>an ALLOCATE statement (6.3.1) containing no STAT= specifier.  It is not
>signaled by an ALLOCATE statement containing a STAT= specifier.  The signaling
>values are the same as the STAT values.  Whether it signals outside enable
>blocks is processor dependent.
>
>DEALLOCATION_ERROR
>This occurs when the processor detects an error when executing a DEALLOCATE
>statement (6.3.1) containing no STAT= specifier.  It is not signaled when
>executing a DEALLOCATE statement containing a STAT= specifier.  The signaling
>values are the same as the STAT values.  Whether it signals outside enable
>blocks is processor dependent.
>
>INSUFFICIENT_STORAGE
>This indicates that the processor is unable to find sufficient storage to
>continue execution.  It may occur prior to the execution of the first
>executable statement of a main program or procedure and it may occur during
>the execution of an executable statement.  It need not signal if
>ALLOCATION_ERROR signals.  It signals outside enable blocks.

How does this interact with the automatic deallocation proposal?
Suppose this condition is signalled in routine A which does not have
a handler for it, and that substantial space is freed when control
is returned to A's caller, B.  Assume B also has no handler for this
condition and that the processor simply continues execution in B,
including a number of operations that successfully allocate and free
memory.  Is the INSUFFICIENT_STORAGE condition still signalling?

>
>BOUND_ERROR
>This occurs when an array subscript, array section subscript, or substring
>range violates its bounds.  This does not include violations of the
>requirements derived from the size of an assumed-size array.  Whether it
>signals outside enable blocks is processor dependent.
>
>SHAPE
>This occurs when an array operation or assignment does not conform in shape.
>Whether it signals outside enable blocks is processor dependent.
>
>MANY_ONE
>This occurs when a many-one array section (6.2.2.3.2) appears on the left of
>the equals in an assignment statement or as an input item in a READ statement.
>Whether it signals outside enable blocks is processor dependent.
>
>NOT_PRESENT
>This occurs when a dummy argument that is not present is accessed as if it
>were present; that is, when one of the restrictions of 12.5.2.8 is violated.
>Whether it signals outside enable blocks is processor dependent.
>
>UNDEFINED
>This occurs when a value that is required for an operation is detected by the
>processor to be undefined.  Whether it signals outside enable blocks is
>processor dependent.
>
>[Footnote: This wording is intended to allow the processor to be as thorough
>as it chooses with respect to the detection of undefined values.]
>
><<15.2 Input/output conditions>>
>
>IO_ERROR
>This occurs when an input/output error (9.4.3) is encountered in an
>input/output statement containing no IOSTAT= or ERR= specifier.  It is not
>signaled when executing an input/output statement containing an IOSTAT= or
>ERR= specifier.  The signaling values are the same as the IOSTAT values.
>Whether it signals outside enable blocks is processor dependent.
>
>END_OF_FILE
>This occurs when an end-of-file condition (9.4.3) is encountered in an input
>statement containing no IOSTAT= or END= specifier.  It is not signaled when
>executing an input statement containing an IOSTAT= or END= specifier.  Whether
>it signals outside enable blocks is processor dependent.
>
>END_OF_RECORD
>This occurs when an end-of-record condition (9.4.3) is encountered in an input
>statement containing no IOSTAT= or EOR= specifier.  It is not signaled when
>executing an input statement containing an IOSTAT= or EOR= specifier.  Whether
>it signals outside enable blocks is processor dependent.
>
><<15.3 Floating-point conditions>>
>
>OVERFLOW
>This condition occurs when the result for an intrinsic real or complex
>operation has a very large processor-dependent absolute value.  Whether it
>signals outside enable blocks is processor dependent.
>
>UNDERFLOW
>This condition occurs when the result for an intrinsic real or complex
>operation has a very small processor-dependent absolute value.  A processor
>that does not conform to IEC 559:1989 is required to set this condition when
>requested to do so by a SIGNAL statement, but is not required to set it
>otherwise.  Whether it signals outside enable blocks is processor dependent.
>
>DIVIDE_BY_ZERO
>This condition occurs when a real or complex division has a nonzero numerator
>and a zero denominator.  Whether it signals outside enable blocks is processor
>dependent.
>
>INEXACT
>This condition occurs when the result of a real or complex operation is not
>exact.  A processor that does not conform to IEC 559:1989 is required to set
>this condition when requested to do so by a SIGNAL statement, but is not
>required to set it otherwise.  Whether it signals outside enable blocks is
>processor dependent.
>
>INVALID
>This condition occurs when a real or complex operation is invalid.  A
>processor that does not conform to IEC 559:1989 is required to set this
>condition for real or complex division of zero by zero and when requested to
>do so by a SIGNAL statement, but is not required to set it otherwise.  Whether
>it signals outside enable blocks is processor dependent.
>
>[Footnote: It is expected that by default the conditions UNDERFLOW and INEXACT
>will not signal except inside enable blocks.]
>
><<15.4 Integer conditions>>
>
>INTEGER_OVERFLOW
>This condition occurs when the result for an intrinsic integer operation has a
>very large processor-dependent absolute value.  Whether it signals outside
>enable blocks is processor dependent.
>
>INTEGER_DIVIDE_BY_ZERO
>This condition occurs when an integer division has a zero denominator.
>Whether it signals outside enable blocks is processor dependent.
>
><<15.5 Intrinsic procedure condition>>
>
>INTRINSIC
>This condition indicates that an intrinsic procedure or operation has been
>unsuccessful.  An unsuccessful intrinsic procedure may signal other conditions
>instead of INTRINSIC.  Whether it signals outside enable blocks is processor
>dependent.  If an intrinsic procedure is an actual argument in a procedure
>call within an enable block for the INTRINSIC condition, the condition must
>signal if the procedure is invoked through the argument association.
>
><<15.6 System error conditions>>
>
>SYSTEM_ERROR
>This condition occurs as a result of a system error.  Whether it signals
>outside enable blocks is processor dependent.
>
><<15.7 Combination conditions>>
>
>Each of the following conditions may be specified on an enable, handle, or
>signal statement and is equivalent to specifying a list of conditions.
>
>STORAGE
>This condition is equivalent to the list: ALLOCATION_ERROR,
>DEALLOCATION_ERROR, and INSUFFICIENT_STORAGE.
>
>IO
>This condition is equivalent to listing all the input/output conditions.
>
>FLOATING
>This condition is equivalent to the list: OVERFLOW, INVALID, and
>DIVIDE_BY_ZERO.
>
>INTEGER
>This condition is equivalent to listing the two integer conditions.
>
>USUAL
>This condition is equivalent to the list: STORAGE, IO, FLOATING, and INTRINSIC.
>
>ALL_CONDITIONS
>This condition is equivalent to listing all the conditions.
>==========================end of text for ballot============================

--
Leonard J. Moss <ljm@slac.stanford.edu>  | My views don't necessarily
Stanford Linear Accelerator Center       | reflect those of SLAC,
MS 97; P.O. Box 4349; Stanford, CA 94309 | Stanford or the DOE
