AI22-0066-1

!standard 3.2.4(21/3)                                   23-03-22  AI22-0066-1/01

!standard 4.4(7/3)

!standard 5.8(5)

!standard 8.5.1(6)

!standard A.10.8(8)

!standard A.10.9(13)

!class confirmation 23-03-22

!status received 23-03-22

!priority Very_Low

!difficulty Easy

!qualifier Omission

!subject If it ain't broke...

!summary

This AI serves as a holder for questions that are not answered (or answered

incorrectly) by the RM, but for which no one doubts the intent.

!issue

Issues (1) through (4) were promoted from AI12-0066-1.

(1) When Ada.Text_IO.Get reads a integer number without a Width parameter, what gets read if the input is "2#101010"? A.10.8(8) says "reads the longest possible sequence of characters matching the syntax of a numeric literal without a point." Read literally, that means reading has to stop after reading the "2", as the entire value does not match the syntax of a numeric literal.

That requires effectively infinite lookahead. The ACATS requires reading the entire string.

(2) Consider:

 

with Text_IO;
procedure Aatsor is
   -- anonymous access to subprogram object renaming

   procedure Foo (X, Y : Integer) is
      use Text_IO;
   begin
      Put_Line ("X =" & Integer'Image (X));
      Put_Line ("Y =" & Integer'Image (Y));
   end;

   Ref : access procedure (Aaa, Bbb : Integer := 111);

   Renamed_Ref : access procedure (Bbb, Aaa : Integer := 222)
      renames Ref;
begin
   Ref := Foo'Access;
   Renamed_Ref.all (Aaa => 333);
end;

 

The correct answer, according to 8.5.1(6), is

  X = 333<NL>Y = 111<NL>

But this doesn't make sense for the corresponding generic case (a formal in out parameter), as how could the body know what the parameters and defaults of the actual are? Something is wrong here.

(3) The predicate-static rules (3.2.4(15-22/3) don't really work for a boolean subtype.

Specifically, the predicate-static rules only allow the current-instance to be used as one of the operands of a relational operator, the operand of a membership, or the selector of a case expression. That means that the following are illegal:

 

subtype Fooey1 is Boolean
        with Static_Predicate => Fooey1; -- ERROR:
subtype Fooey2 is Boolean
        with Static_Predicate => Fooey2 or Debug; -- ERROR:

 

In both of these cases, the current instance is not in one of the places allowed for a predicate-static expression.

(4) The wording of 12.2(2) isn't quite right.

If the generic body is a child of a generic package, then its elaboration establishes that each corresponding declaration nested in an instance of the parent (see 10.1.1) can from then on be

instantiated without failing the Elaboration_Check.

Consider how this wording applies to the elaboration of the (one and only) generic body in this example:

 

generic package G1 is end;
generic package G1.G2 is end;
generic package G1.G2.G3 with Elaborate_Body is end;
package body G1.G2.G3 is end;

with G1;           package I1 is new G1;
with I1, G1.G2;    package I2 is new I1.G2;
with I2, G1.G2.G3; package I3 is new I2.G3;

 

I3 is instantiating I2.G3 after the body of G1.G2.G3 has been elaborated.

We want the elaboration check to pass, but this does not follow from a strict reading of the wording.

In this context, the phrase "the parent" obviously refers to G1.G2. There are no instances of G1.G2 anywhere in this example. There is an instance of I1.G2, but that's not the same thing.

(5) The language is inconsistent as to how it describes when a variable is required.

Some rules require that something denote a variable, for instance 6.4.1(5): "If the mode is in out or out, the actual shall be a name that denotes a variable." and 13.11(15): "Storage_Size or Storage_Pool may be specified for a nonderived access-to-object type via an attribute_definition_clause; the name in a Storage_Pool clause shall denote a variable."

Other rules just require that something be a variable, for instance 3.10.2(25): "If A is an access-to-variable type, then the view shall be a variable; ..." and 5.2(5/2): "The target [denoted by the variable_name] shall be a variable of a nonlimited type."

We even have some that use both forms, for example 13.11.3(5.2/4): "Otherwise, the expected type for the Default_Storage_Pool aspect is Root_Storage_Pool'Class and the aspect_definition shall be a name that denotes a variable."

(6) 5.8(5) says that "The execution of a goto_statement transfers control to the target statement...". But nothing either in 5.8 or 5.1 tells us what happens afterwards. What does happen?

!recommendation

Make no changes to the Reference Manual.

!discussion

For these questions, we believe that adding proper wording to the Standard would be much more likely to introduce bugs than to clarify anything. Many of these issues date to Ada 83, yet they've never been addressed.

(1) A friendly reading of the wording is that characters are read so long as the string read could be legal (if incomplete) syntax of a numeric literal. This matches the behavior of the ACATS (and ACVC before it); it has always required reading the entire value of "2#101010".

Since this wording has existed since Ada 83, and the strict reading in the question requires nonsense (implementing the effect of infinite lookahead would be expensive and would have undesirable effects on interactive reading), we believe that there is no real issue with the wording. Fixing it just would just make the wording more complex and introduce more opportunities for problems.

A.10.9(13) raises similar issues for real literals.

(2) The problematic generic case is:

declare
   generic
      Formal_Obj : in out

         access procedure (Aaa, Bbb : Integer := 111);
   procedure G;
   procedure G is
   begin
      Formal_Obj.all (Aaa => 333);
   end;

   Actual_Obj : access procedure (Bbb, Aaa : Integer := 222);

   procedure Iii is new G (Formal_Obj => Actual_Obj);

   procedure P (X, Y : Integer) is
      use Text_Io;
   begin
      Put_Line ("X =" & X'img);
      Put_Line ("Y =" & Y'img);
   end;
begin
   Actual_Obj := P'access;
   Iii;
end;

 

We'd destroy the generic contract model if the body of the generic had to somehow know the parameter names and defaults of the actual. (That would be especially problematic if the actual had different names for the parameters.)

So, we need to either (A) require full conformance when renaming or instantiating objects with access-to-subprogram types, or (B) adopt a rule like 8.5.4(7) for object renamings and formal in out parameters.

(A) is easy but potentially incompatible; (B) is likely to be a significant amount of work. But the problematic case is rarely likely to happen in practice (generic formal in out parameters are rarely used; anonymous access-to-subprogram types are rarely used outside of parameters, that means that using them together is rare squared). Indeed, this is so unlikely that we don't think it is worth fixing; the disruption to compilers outweighs any likely benefit to users.

(3) The simple fix of just adding a bullet "the current instance" doesn't work because it would allow the current instance on the both sides of operators, which is not intended or desired. So a correct fix is relatively expensive.

Moreover, there is an easy workaround to this problem: add "= True" to the expression:

subtype Fooey1 is Boolean
        with Static_Predicate => Fooey1 = True; -- OK.
subtype Fooey2 is Boolean
        with Static_Predicate => (Fooey2 = True) or Debug; -- OK.

 

One also can easily write a range for any possible subtype of Boolean; it's never necessary to use a static predicate in the way that it might for an enumeration type with more than 2 literals.

Finally, a constrained subtype of a boolean type is essentially a pathology. Such a subtype is either the same as Boolean without the constraint, or is a subtype with zero or one values - something that is not going to be useful in conditional expressions or statements. (Such a subtype is essentially equivalent to a Boolean constant.)

Since this is a relatively useless construct, and the wording needed is relatively complicated and only useful for this construct, we choose not to fix this.

(4) Fixing this probably would require a term (as the definition is recursive). Something like the following:

The "ultimate corresponding generic unit" of a generic unit G is defined to be:

Then the present wording could be fixed to use this new term:

If the generic body is a child of a generic package (see 10.1.1), then its elaboration establishes that any generic unit whose ultimate corresponding generic unit is that child unit can from then on be instantiated without failing the Elaboration_Check.

However, this isn't quite right, as it wouldn't cope properly with

generic package G1 is
   package Nested_Nongeneric is
      generic package G2 is
      end;
   end;
end;

package I1 is new G2;
package I2 is new I1.Nested_Nongeneric.G2;

 

where the name G1.G2 doesn't make sense.

This is complicated enough, and the likelihood that anyone would get the wrong answer is low enough, that we don't attempt to fix it.

(5) It would be best to consistently define such rules, perhaps by ensuring that all of the rules can use "denotes a variable", so that searching for all rules of this kind would be practical. (Variable appeared 108 times in a recent AARM, so looking for that alone is not practical.)

But redoing wording throughout the standard is not appealing and would not have enough benefit.

(6) 5.1(15) describes how a complete sequence_of_statements executes, but it gives no hint on what happens after control is transferred to a labeled statement. There should be some text that says that in that case, the labeled statement is executed, followed by individual following statements in succession until the enclosing sequence_of_statements is completed or a

transfer of control occurs. But it's highly unlikely any user or implementer would be confused, and as usual, adding wording would have risks of being incorrect in some unusual case. Additionally, AI22-0013-1 suggests more significant changes to the model of labels; it would make more sense to repair this in the context of a more significant change (if it every happens).

!ACATS test

Since we're not making any changes to the language, no tests are required.

!appendix

Some of the mail in the !appendix of AI12-0066-1 is relevant to issues (1),

(2), (3), (4), and (5).