AI22-0072-1
!standard 8.6(17.1/5) 24-03-20 AI22-0072-1/06
!class binding interpretation 23-04-04
!status Amendment 1-2022 23-10-05
!status WG9 Approved 24-06-10
!status ARG Approved 12-0-0 23-10-05
!status work item 23-04-04
!status received 23-02-22
!submitter Randall Brukardt
!priority Low
!difficulty Easy
!qualifier Omission
!subject Meaning of direct references to components
A direct_name denoting a discriminant or protected component (other than in a record representation clause) is interpreted as the discriminant or protected component of the current instance of the enclosing type.
The RM does not define the meaning of direct_names of discriminants and protected components used within a type declaration (including a protected declaration) as an object. But this is needed to apply many rules, including Legality Rules and various semantic rules.
(See Summary.)
Add after 8.6(17.1/5): [this is directly after the definition of "current instance"]
AARM Ramification: This rule doesn’t apply to the selector_name of an aggregate or discriminant_constraint, since a selector_name is not a direct_name (even though both usually are identifiers).[e]
AARM Discussion: If there is a prefix, either the name is an expanded name, which is already defined to be a reference to the current instance of the type by a rule in 4.1.3, or some form of selected_component for which the prefix determines the object to use.
[Editor's note: This echoes the definition of “current instance”, so it will fit well. A protected or task body is considered part of the declarative region of the type_declaration (that has to be true so the current instance rule works), so we don't need to mention those bodies.]
The properties of the current instance affects legality of component references as well as the dynamic semantics. For example:
type Acc is access all Some_Type;
protected Stack is
procedure Push (Item : in Acc);
function Pop return Acc;
private
Stack_Head : Acc := null;
end Stack;
protected body Stack is
function Pop return Acc is
Temp : Acc := Stack_Head;
begin
Stack_Head := Stack_Head.Next; -- Illegal.
return Temp;
end Pop;
procedure Push (Item : in Acc) is
begin
Item.Next := Stack_Head;
Stack_Head := Item; -- OK.
end Push;
end Stack;
The line marked Illegal isn't allowed because Stack_Head refers to the protected component of the current instance of Stack, and the current instance is a constant inside a protected function.
But there is no rule in the Standard that says that Stack_Head refers to the component of the current instance.
Similarly, in
type Rec (D : Natural) is record
S : String (1 .. D); -- D here is that of the current instance.
end record;
we ought to know that D refers to the discriminant of the current instance.
Because of this, this seems too important to leave to the ACATS to define (and the ACATS has a number of tests, some as old as the ACVC, that test this expectation).
[Editor's note: The other items of AI12-0066-1 are covered in AI22-0064-1, AI22-0067-1, and AI22-0066-1 (which is the counterpart of AI12-0066-1 for Ada 2022).]
----
We have to complicate the wording a bit, as a single_protected_declaration is not a type_declaration. It declares an anonymous type, and a named object. We still need a version of this rule to apply in the body of a single protected object. We don’t have to cover single_task_declarations because they cannot have components or discriminants.
We also have to worry about the handful of uses of component names to directly identify components. We know of three such uses: as selector_names in aggregates, selector_names in discriminant constraints, and as local_names in record_representation_clauses. We don’t have to cover selector_names as they are not direct_names (even though both are identifiers). We add an exception for the latter case to exclude the local_names of a record_representation_clause from the rules, in the same way that the current instance rule for types has exceptions.
----
Note that a single_protected_declaration does not have a current instance (AARM 8.6(17.a/2) says this). However, almost all of the rules of protected units (as well as the discussion above!) assume that the anonymous type of a single protected object does indeed have a current instance. For instance, the target object of an internal call is defined to be the current instance of the protected unit (see 9.5(3/3)). Since there is no current instance for a single protected object, the target object seems ill-defined (even though the intent is obvious). There are many other such rules. This problem is pervasive and long-standing (many of the rules involved are original Ada 95 rules). As such, it should be handled in a separate AI (the definition of “current instance” requires the existence of a usage name, and if no such name exists, as for the anonymous type of a single protected object, how to extend the definition is not obvious).[f][g]
@dinsa
@xindent{Within an @fa{aspect_specification} for a type or subtype, the current instance represents a value of the type; it is not an object. Unless otherwise specified, the nominal subtype of this value is given by the subtype itself (the first subtype in the case of a @fa{type_declaration}), prior to applying any predicate specified directly on the type or subtype. If the type or subtype is by-reference, the associated object of the value is the object associated (see @ref{6.2}) with the evaluation of the usage name.}
@dinst
@xbullet{If a usage name that is a @fa{direct_name} appears within the declarative region of a @fa{type_declaration} or @fa{single_protected_declaration} and denotes a component of that same @fa{type_declaration} or @fa{single_protected_declaration}, then it is equivalent to a @fa{selected_component} that denotes the corresponding component of the current instance of that @fa{type_declaration} or of the object of that @fa{single_protected_declaration}. This rule does not apply to a @fa{local_name} within a @fa{record_representation_clause}.}
These rules have been assumed by the ACATS going back to the original ACVC; further testing should not be needed.
[a]I am still not sure this is necessary. What else could such a direct_name within a single_protected_declaration denote other than the corresponding component of the object of the single_protected_declaration?
If you are convinced this is necessary, then I believe you need to include single_task_declaration, since they have discriminants.
I would leave them both out, as there really can't be any ambiguity. But I think we definitely need both or neither to be consistent.
[b]We need to define what these do. One doesn't get to assume. And single_task_types do not have a discriminant part.
[c]Good point about single tasks -- no discriminants!
As mentioned, I don't see the need to say anything about a direct_name that denotes a component declaration occurring within a single_protected_declaration, as the only thing it could possibly denote is a component of the single protected object.
But I have said that several times now without convincing you, so I guess we will need to resolve it in the next ARG meeting while reviewing this AI ...
[d]I just ran across an old e-mail thread that noted this equivalence is needed so that rules on selected components (such as 4.1.3(15)) clearly apply to this reference. Else we might be missing some checks (both legality and runtime).
[e]Thanks to Tucker for pointing this out.
[f]Tuck will create an AI on this.
[g]That became AI22-0089-1.