Version 1.2 of ai12s/ai12-0326-1.txt

Unformatted version of ai12s/ai12-0326-1.txt version 1.2
Other versions for file ai12s/ai12-0326-1.txt

!standard 5.5.3(17/5)          19-04-15 AI12-0326-1/02
!standard 5.5.3(21/5)
!class Amendment 19-04-05
!status work item 19-04-05
!status received 19-03-19
!priority Low
!difficulty Easy
!subject Consequence for incorrect Allows_Exit
!summary
It is a bounded error if an Allows_Exit subprogram handles an exception in a when-others handler but does not re-raise the exception.
!problem
AI12-0189-1 introduced the Allows_Exit aspect to specify that a subprogram is designed to allow use in a parallel iterator.
However, that AI did not provide any consequence if the subprogram violates the assumptions of the aspect. This is bad, since it requires the implementation to work properly regardless of what the subprogram with the Allows_Exit aspect does.
For instance, if an implementation choses to use exceptions to implement exits from procedural iterators, a routine that specifies Allows_Exit but still "eats" all exceptions propagated from calls to the access-to-subprogram parameter could cause problems.
!proposal
(See Summary.)
!wording
[Author's note: Paragraph numbers in this AI are from draft 19 of the Ada 2020 RM.]
Add after 5.5.3(21/5):
Bounded Error
If a subprogram S has a True Allows_Exit aspect and is used in an iterator_procedure_call, it is a bounded error if S handles an exception in a when others exception handler but does not re-raise the exception. The possible effects are:
* the propagation of Program_Error;
* the propagation of an exception raised by S;
* the termination of the loop_statement with the procedural_iterator as its iteration_scheme as though the loop_statement completed normally rather than by a transfer of control;
* the continued execution of the loop_statement even though some iteration ended with a transfer of control.
AARM Reason: We want to permit implementations to use normal exceptions to implement a transfer of control out of the loop_statement.
AARM Implementation Note: We allow subprogram S to invoke the anonymous local procedure P from a parallel construct. This implies that the implementation should not implicitly declare variables global to the loop_statement to carry information about the transfer of control that caused the loop_statement to complete. Instead it needs to encode the information in, for example, the Exception_Information that accompanies an exception used to signal the transfer of control, or in some sort of per-thread storage.
!discussion
This AI attempts to define what we expect of a subprogram S that has the Allows_Exit aspect True, meaning that it does not rely on exception handling to do cleanup, but instead relies on finalization.
We have chosen to make this a bounded error rather than erroneous because the semantics of this construct are defined by equivalence with a currently legal construct, where the subprogram S would be allowed to do essentially anything it wanted to. We are reluctant to introduce erroneousness when the expansion has well-defined semantics under the same circumstances.
Another concern that was identified during (private) discussion on this topic was the use of parallel constructs in Allows_Exit routines. We have chosen to allow the implementor of an Allows_Exit subprogram to use a parallel construct, since the whole point of the procedural iterator might be to create a more sophisticated parallel iteration of some sort. But this implies the Ada implementation must not presume it can use variables that are global to the loop to carry information about the nature of the transfer of control. Instead, it needs to be encoded in the Exception_Information accompanying the "abort exception" being used to signal the transfer of control. Again, our view is that this is a new feature, and there is no reason to permit more implementation dependence than necessary. Therefore we clarify that a use of a parallel construct is permitted, and the implementation needs to handle that properly.
!ASIS
None needed (anything needed would be part of the original mechanism).
!ACATS test
Erroneous execution cannot be tested by definition.
!appendix

From: Randy Brukardt
Sent: Tuesday, March 19, 2019  12:52 AM

AI12-0189-1 defined the Allows_Exit aspect to assert that a particular 
subprogram is prepared to allow arbitrary transfers of control from the
subprogram represented by one of its parameters. In particular, it is not
supposed to use exception handling to do cleanup. (I'm not sure why that's
specifically a problem; it's more that it shouldn't be allowed to "eat" any
exceptions coming from the subprogram -- although using finalization for 
cleanup is probably better.)

Anyway, there doesn't seem to be any consequence if the assertion is violated,
especially when used in a procedural_iterator. That seems wrong; it undermines
the point of having the aspect in the first place.

For instance, imagine an implementation that uses a special unnamable (but
handle-able) exception to implement transfers of control for a 
procedural_iterator. And imagine that we have a procedure defined thus:

     procedure Bad_Guy (A : access procedure (...))
        with Allows_Exit is
     begin
         ...
         A (...);
         ...
     exception
         when others => null;
     end Bad_Guy;

If we have a procedural_iterator thus:

     for (Q) of Bad_Guy loop
        if Match(Q) then
           Save_It;
           goto Skip;
        end if;
     end loop;
     Not_Found;
   <<Skip>> null;

This loop is legal, but it probably will execute Not_Found even when Match is 
True. It defeats the purpose to have a declaration for this property if a 
routine that violates it has no consequence -- an implementation would still 
have to work overtime to make this work, even though Bad_Guy ate the special 
exception despite its promise not to do that.

So I think we need an Erroneous Execution rule for this case. Perhaps 
something like:

   If a subprogram S has a True Allows_Exit aspect, and it is used in an 
   iterator_procedure_call, execution is erroneous if S handles any exceptions 
   propagated from a call of any access-to-subprogram parameter of S.

[or, if we wanted to just have a guarantee that S doesn't eat any propagated
exceptions:

   If a subprogram S has a True Allows_Exit aspect, and it is used in an 
   iterator_procedure_call, execution is erroneous if S does not propagate any 
   exceptions propagated from a call of any access-to-subprogram parameter of S.

but the wording of Allows_Exit seems pretty clear that this is not the intent.]

Do we need an AI for this?? (Or possibly put it into a clean-up AI?)

****************************************************************


Questions? Ask the ACAA Technical Agent