AI22-0045-1

!standard 2.8(6/5)                                    22-06-16  AI22-0045-1/01

!standard 2.8(7/3)

!standard 2.8(7.1/3)

!standard 2.8(7.2/3)

!standard 2.8(12)

!class binding interpretation 22-06-16

!status work item 22-06-16

!status received 22-03-22

!priority Medium

!difficulty Medium

!qualifier Clarification

!subject Issues with pragma placement

!summary

*** TBD.

!issue

(1) One would expect that a pragma Assert is a master. We would not want function results from the evaluation of an Assert expression hanging around. AI22-0013-2 attempted to clarify this by modifying 2.8(12) to say:

Any pragma that appears at the place of an executable construct is executed, and is treated for the purposes of other rules of the language as being of the same sort of executable construct. Unless otherwise specified for a particular pragma, this execution consists of the evaluation of each evaluable pragma argument in an arbitrary order.

In the case of a pragma replacing a statement as allowed by 2.8(7.1/2), it is clear that the pragma is treated as a statement. Unfortunately, a statement is not a master construct (that requires a simple_statement), so it appears that a pragma given at the place of a statement is not a master (or at a minimum it is not clear). Since the point of AI22-0013-2 was to clarify questions like this, further clarification is needed.

(2) However, most of the rules of 2.8 are not as clear about the construct that the pragma is at the place of. In particular, 2.8(6/5) ["after a semicolon delimiter"] does not talk about constructs at all. Moreover, multiple placement rules could apply: for example, a pragma following a statement in a sequence_of_statements is allowed by both 2.8(7.1/3) (which is clear about the construct "at the place of") and 2.8(6/5) (which is not). How do we decide which rule is the reason the pragma is allowed at a particular place?

(3) Some of the places that pragmas are allowed are not at the place of any executable construct. What happens for executable pragmas in such locations? When are they executed? Are they a master? And so on.

For example, 2.8(7/3) allows a pragma at the place of an _alternative; this allows a pragma at the head of a case statement:

        

case P is
  pragma Assert (...)  -- (1)
  when 1 => ...           -- (2)
          pragma Assert (...) -- (3)
  when others => ...
end case;

 

It is clear that (3) is at the place of a statement, and thus is executed after the statements at (2) (and only if the statements at (2) are executed). But (1) is not at the place of a statement (it is in place of a case_statement_alternative), and this part of a case statement is never executed.

(4) Ai12-0236-1 modified 2.8(6/5) to disallow pragmas in declare_expressions. However, a declare_expression contains a list of declare_items. Therefore, 2.8(7/3) allows pragmas in the list of declare_items, specifically the place that 2.8(6/5) is trying to disallow. Something is wrong here.

!recommendation

For (1), we explicitly state the kinds of constructs that are being executed.

For (3), we make no change, as only pragma Assert is involved and it specifically has a rule to prevent this problem.

For (2), this version of the AI makes no recommendation. [** the ARG needs to decide on an approach and assign someone to complete a proposal. **]

For (4), this version of the AI makes no recommendation; possibly the solution to (2) will also solve (4). [** The ARG needs to decide whether some or all pragmas should be allowed in declare_expressions **]

!wording

Modify 2.8(12): (Note: This includes the approved  modification of                      AI22-0013-2, which is not yet in any published draft).

Any pragma that appears at the place of an executable construct is executed{, and is treated for the purposes of other rules of the language as being a simple_statement if it appears at the place of a statement, or a basic_declaration if it appears at the place of a declarative_item}. Unless otherwise specified for a particular pragma, this execution consists of the evaluation of each evaluable pragma argument in an arbitrary order.

*** TBD: A fix for (2) and for (4).

!discussion

For (1), we should explicitly state the sort of constructs that we are "in the place of". This should eliminate any grey area when answering semantic questions about the execution of a pragma.

For (2), the least obtrusive fix would be to attempt to eliminate 2.8(6/5) altogether. The author does not know of any places allowed by that rule that are not allowed by some other rule (especially 2.8(7/3)). (If we go this way, this would need to be checked carefully.) In the absence of that rule, the other rules all provide at least some idea of what construct is being replaced by a pragma. If there are places allowed by 2.8(6/5) that aren't allowed by one of the other rules, we could add rule(s) for those explicitly.

A more general fix would be to replace 2.8(6/5, 7/3, 7.1/3, and 7.2/3) with actual syntax placement rules. This idea was rejected in AI05-0163-1 was "requiring the inspection of more than 100 BNF rules". Tucker Taft suggests that modification of 5 rules would allow all of the places people really care about.

        simple_statement ::= ... | pragma

        library_unit_declaration ::= ... | pragma

        context_item ::=  ... | pragma

        aspect_clause ::=  ... | pragma

        generic_formal_part ::= generic

                        {generic_formal_parameter_declaration | use_clause | pragma}

           

The use of aspect_clause cleverly allows pragmas in virtually all sorts of declarations.

However, these rules would not allow pragmas in a few places the current rules allow, including between the "is" and first "when" of a case statement, between the "select" and an alternative for select_statements. These positions are only likely to be useful for lexical pragmas like pragma Page and pragma List(Off), and even then it seems bizarre to split a statement in a listing. Can we eliminate these locations? (Tucker suggested checking the GNAT code database for such placements; an AdaCore employee needs to volunteer to do that if we want to consider this.)

For (3), pragmas that require execution, but that are not at the place of an executable construct, should be illegal. Implementations should not be required to invent mechanisms solely to ensure that oddly placed can be executed.

For pragma Assert, there already is a rule (11.4.2(4/2)) which prevents pragma placements like the first one in the third Issue. There are not any other language-defined pragmas that need to execute, so there is not actually a language problem.

However, it still is unusual to have two necessary rules in very different parts of the RM, especially as it would be easy for new pragmas to forget the required placement rule. We could fix this by defining a name for such pragmas, perhaps as the follows:

A pragma that *requires execution* shall appear in the place of an executable construct. Specific pragmas that require execution are identified throughout this document.

And then replace 11.4.2(5/2) with "Pragma Assert requires execution.".

This isn't obviously better, so the author is not proposing it.

For (4), the appropriate fix depends on two factors:

   (A) Whether we still want to ban pragmas in declare_expressions; and

   (B) how we chose to solve issue (2).

Assuming that we still want to ban pragmas in declare_expressions, then if, for (2), we decide to explicit add pragmas to the grammar, then we need to do nothing (as pragmas would need to be explicitly added to declare_expressions to allow them). If we do not, then we need to add an

exception to 2.8(7/3) excluding declare_expressions from this rule.

At press-time, a suggestion was made to allow pragmas in declare expressions so that a pragma Assert could be included. (Author's aside: note that the placement rule 11.4.2(5/2) would not allow pragma Assert in a declare expression even if it was included in the grammar and/or the placement rules of 2.8, since a declare expression does not contain basic_declarative_items. Both this rule and the proposed 2.8(12) would need modification to allow pragma Assert in a declare expresion. This issue was included in this AI in part because it affects the wording needed for solving the other issues.)

The intent of all of the rules surrounding declare expressions was to keep the implementation extremely simple, and to allow an entire expression to be the smallest unit of change in a compiler. Changing properties in the middle of an expression could be problematic for some implementations, and it did not seem important enough of a capability to require implementation to change their basic design.

For example, is it important to allow the specification of pragma Suppress and (especially, since it cannot be ignored) pragma Unsuppress in the middle of an expression? Consider this:

procedure P is
   pragma Suppress (All_Checks);
begin
   A := B + (declare
                pragma Unsuppress (All_Checks);
             begin
                C * D);
end P;

 

If the implementation normally suppresses overflow checks in the scope of a pragma Suppress, the pragma Unsuppress would have to turn the checks back on - an overflow check is required at the multiply in the above. However, if the implementation uses global flags to control overflow and expressions are evaluated at one time, it would require substantial efforts to get this example to work. (Similar issues apply to other pragmas that affect global settings, such as Optimize.)

These sorts of expressions were designed to be used in assertions like predicates and preconditions. Those are not even evaluated where they are declared, so one would have to be able to defer the effect of a pragma until some later point. For some pragmas, that would be a new capability. (The author also wonders about putting an (pragma) assertion inside of another assertion; it seems unusual.)

The author believes that allowing pragmas in declare expressions should be limited only to specific pragmas that have been determined to be safe, and others not be allowed (or at least, not be required to be allowed).

!examples

(See Issue and Discussion.)

!ACATS test

** TBD.

!appendix

This AI in partially in response to ARG Github Issues #7 (https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues/7) and #9 (https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues/9).

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