Version 1.2 of ais/ai-00416.txt

Unformatted version of ais/ai-00416.txt version 1.2
Other versions for file ais/ai-00416.txt

!standard 3.9.2(2)          05-02-13 AI95-00416/02
!class amendment 05-02-07
!status work item 05-02-07
!status received 05-02-07
!priority High
!difficulty Hard
!subject Access results, accessibility, and return statements
!summary
Dispatching on access result is supported.
Tasks are activated after returning from a function that returns an object containing tasks.
Accessibility levels are defined both for the call site, and at the point of the return statement, which is important for objects with access discriminants and for objects of a class-wide type.
!problem
We have not fully specified the rules for functions with anonymous access type as a result type. In particular, how do they work with dispatching and what are the accessibility rules.
We have also not specified the details for result types with access discriminants, as these have special accessibility considerations.
In general, we need to specify the accessibility level of the "return object" given that it might be aliased, have access discriminants, be an object of an anonymous access type, etc.
We also need to specify some of the details of what happens if the return object has a controlled or task part.
!proposal
Dispatching on access result is possible. For example:
function Empty_Acc return access T;
function Similar(X : access T; Y : access T) return Boolean; ...
M : access T'Class := ... B : Boolean := Similar(M, Empty_Acc);
The tag of M.all determines which overriding of Empty_Acc is invoked. A call on a function with a controlling access result may be dereferenced and still be a dynamically tagged or tag indeterminate expression.
Defaults for controlling access parameters should be permitted, so long as they are functions with controlling access results.
---------------------
Caller does not pass in an accessibility level for return objects.
Return object has accessibility between the uplevels of the function and the return statement. Hence:
Ok for return object to point to up-levels Ok for locals of return statement to point to return object Not Ok for locals outside return statement to point to return object Not Ok for up-levels to point to return object Not Ok for return object to point to locals
Function call has accessibility level of function decl, so may not use call on local function to initialize object in longer-lived heap if it has an access discrim or is of a class-wide type.
If access discriminants are initialized individually, then type conversion provides for the accessibility checks. However, if the access discriminants are not specified individually, but rather come from a named constrained subtype, or from an initializing object, then there is no type conversion involved, and hence we need an explicit rule for the needed accessibility check. This is relevant at a function return and at an allocator. At a function return, we can be returning a record aggregate (access discriminants given individually), an extension aggregate (access discriminants could come from ancestor part, either from an object or named constrained subtype, or from individual values specified after the "with"), a part of an existing object, a part of a function call (level based on level of function decl). At an allocator we have all of these possibilities, plus we have an unitialized allocator where the subtype_indication denotes a named constrained subtype, or an uninitialized allocator where the subtype_indication contains an explicit constraint (access discriminants specified individually).
When using a part of a function call as a prefix for an access discriminant, the level of the function decl determines the accessibility level. I.e. accessibility level of type of access discriminant of a part of a function call is determined by the level of the function decl. When taking 'Access of a part of a function call, the level is that of the innermost master (i.e., the function call corresponds to a temporary object).
Define this as equivalent to converting each access discriminant to the type of the access discriminant of the target.
---------------------
Tasks are not activated until outermost enclosing object fully and successfully initialized, and certainly not prior to return, since only caller knows extent of outermost enclosing object. A return object that is not successfully initialized, is finalized prior to exiting the return statement.
---------------------
For a limited function return, the caller has to control where the return object is built. If the result subtype is unconstrained, while the call is being used to initialize a constrained object, including a component, the space available to the object is bounded. To avoid overrunning this space, the caller must pass in some sort of implicit parameters which will allow the return statement to determine the limits on the space it may occupy. One possibility is to pass in the values for the discriminants, or perhaps to preeinitialize them in the space for the return object. There should be an implementation permission to allow raising Constraint_Error at the beginning of the return statement, prior to fully evaluating the return expression or executing the handled sequence of statements. Something analogous to a 'Constrained bit can be provided, to indicate whether the discriminant values are preinitialized.
!wording
Change first sentence of 3.2.3(1):
An operation operates on a type T if it yields a value of type T, if it has an operand whose expected type (see 8.6) is T, or if it has an access parameter {or access result type} (see 6.1) designating T.
Change 3.7(27/2) to:
For an access discriminant, an access_definition is elaborated when the value of the corresponding access discriminant is defined: by evaluation of its default_expression, by elaboration of a discriminant_constraint, or by an assignment that initializes the enclosing object.
Add to end of 3.9.2(2/2):
{Similarly, if the call is to a function with access result type designating T, then the call has a controlling access result, and the context can similarly control dispatching.}
Change 3.9.2(4):
... if it is a call with a controlling result {or access result}, ...
Change 3.9.2(5):
... or it is a call with a controlling result {or access result} and ...
Change 3.9.2(6):
... if it is a call with a controlling result {or access result}, ...
Delete the second sentence of 3.9.2(11):
The default_expression for a controlling formal parameter of a dispatching operation shall be tag indeterminate. [A controlling formal parameter that is an access parameter shall not have a default_expression.]
Delete 3.9.2(11.b) (it explained the second sentence of 3.9.2(11)).
Change 3.9.2(18/2):
* If the call has a controlling result {or access result} and {(possibly parenthesized or qualified)} is itself{, or designates,} a [(possibly parenthesized or qualified)] controlling operand of an enclosing call on a dispatching operation of a descendant of type T, then its controlling tag value is determined by the controlling tag value of this enclosing call;
Change 3.9.2(18.1/2):
* If the call has a controlling result {or access result} and {(possibly parenthesized, qualified, or dereferenced)} is the [(possibly parenthesized or qualified)] expression of an assignment_statement whose target is of a class-wide type, then its controlling tag value is determined by the target;
Add after 3.10.2(7/2):
AARM NOTE:
This rule defines the accessibility of all named access types, as well as the accessibility level of all anonymous access types other than those for access parameters and access discriminants. Special rules exist for the accessibility level of such anonymous types. Components, stand-alone objects, and function results whose (anonymous) type is defined by an access_definition have accessibility levels corresponding to named access types defined at the same point.
Ramification: {AI95-00230-01} Because accessibility level
is determined by where the access_definition is elaborated, for a type extension, the anonymous access types of components (other than access discriminants) inherited from the parent have the same accessibility as they did in the parent; those in the extension part have the accessibility determined by the scope where the type extension is declared. Similarly, the types of the non-discriminant access components of a derived untagged type have the same accessibility as they did in the parent.
Change 3.10.2(9) as follows:
* The accessibility level of a view conversion{, qualified expression, or parenthesized_expression,} is the same as that of the operand.
Replace 3.10.2(10/2) with:
* The accessibility level of the result of a function call that is used as a prefix of a name or as the actual parameter in a call is that of the nearest enclosing master. In other contexts, the accessibility level is that of the object being initialized from the function result.
AARM Note:
Even though the level of a function result is defined to be that of the nearest enclosing master, the level of an access discriminant of a function result is defined to be that of the function declaration (see 3.10.2(12/2) below).
Add after 3.10.2(10/2):
* Within the handled_sequence_of_statements of an extended_return_statement, the accessibility level of the return object is that of the execution of the return_statement. Redundant[Upon return from the function, the accessibility level of the return object is determined by the point of call.]
AARM Note:
We define the accessibility level of the return object during the handled sequence of statements to be that of the return statement so that the object may be designated by objects local to the return statement, but not by objects outside the return statement. In addition, the intent is that the return object gets finalized if the return statement ends without actually returning (e.g. due to propagating an exception, or a goto).
Delete 3.10.2(11.1/2) (it is redundant).
Change 3.10.2(12/2) to be:
* For an access discriminant, the accessibility level of its anonymous access type is determined as follows:
+ For an access discriminant whose value is determined by a discriminant_association in a subtype_indication, the accessibility level of the object or subprogram designated by the associated value;
AARM NOTE: This deals with the following cases:
- Extension aggregate where ancestor part is a subtype_mark denoting a constrained subtype; - Uninitialized allocator where subtype_indication defines a constrained subtype; - Discriminant of object with a constrained nominal subtype, including constrained components, the result of calling a function with a constrained result subtype, the dereference of an access-to-constrained subtype, etc.
+ For an access discriminant of an object defined by an aggregate where the value of the discriminant is determined by a component_association in the aggregate, the accessibility level of the object or subprogram designated by the associated value;
+ For an access discriminant of an object with an unconstrained nominal subtype that represents part of the result of calling a function, the accessibility level of the function;
+ For an access discriminant of any other object with an unconstrained nominal subtype, the accessibility level of the object.
AARM NOTE: In other words, if you know the value of the discriminant
from a discriminant constraint or an aggregate component association, then that determines the accessibility level; if you don't know it, then it is based on the level of the function that returned the object, or on the object itself if it was not returned by a function. We don't actually define the level of the object returned by a function to always be that of the function, since it might actually have a much shorter lifetime (or longer, for that matter).
Delete 3.10.2(12.a/2) (it was moved up to be after paragraph 7/2).
Delete 3.10.2(13.2/2) (it is redundant).
Add after 4.8(5.1/2):
If the designated subtype of the type of the allocator has one or more unconstrained access discriminants, then the accessibility level of the anonymous access type of each access discriminant, as determined by the subtype_indication or qualified_expression of the allocator, shall not be statically deeper than that of the type of the allocator (see 3.10.2).
Change 4.8(7/2):
... is not deeper than that of the type of the allocator. {If the designated subtype of the allocator has one or more unconstrained access discriminants, then a check is made that the accessibility level of the anonymous access type of each access discriminant is not deeper than that of the type of the allocator.} Program_Error is raised if [this] {either such} check fails.
Add after 6.5(5.3/2):
If the result type is class-wide, the accessibility level of the type of the return_expression shall not be statically deeper than that of the master that elaborated the function body. If the result subtype has one or more unconstrained access discriminants, the accessibility level of the anonymous access type of each access discriminant, as determined by the return_subtype_indication or the return expression, shall not be statically deeper than that of the master that elaborated the function body.
AARM NOTE:
We know that if the result type is class wide, then there must be a return expression. Similarly, if the result subtype is unconstrained, then either the return_subtype_indication (if any) is constrained, or there must be a return expression.
Add after 6.5(5.5/2):
AARM NOTE:
If the result type is controlled or has a controlled part, appropriate calls on Initialize or Adjust are performed prior to executing the handled_sequence_of_statements, unless of course if the initial expression is an aggregate (which requires build-in-place with no call on Adjust).
Change 6.5(6/2):
For the execution of a {simple_}return_statement, ...
Add after 6.5(6/2):
If the return object has any parts that are tasks, the activation of those tasks does not occur until after the function returns (see 9.2).
AARM NOTE:
Only the caller can know when task activations should take place, as it depends on the context of the call. If the function is being used to initialize the component of some larger object, then that entire object must be initialized before any task activations. Even after the outer object is fully initialized, task activations are still postponed until the "begin" at the end of the declarative part if the function is being used to initialize part of a declared object.
Change 6.5(20.1/2):
If the result type is class-wide, a check is made that the accessibility level of the type identified by the tag of the result is not deeper than that of the master that elaborated the function body. {If the result subtype has one or more unconstrained access discriminants, a check is made that the accessibility level of the anonymous access type of each access discriminant, as determined by the return_subtype_indication or return expression, is not deeper than that of the master that elaborated the function body.} If [this] {either} check fails, Program_Error is raised.
Add after 6.5(22/2):
Implementation Permission
If the result subtype of a function is unconstrained and limited, and a call on the function is used to provide the initial value of an object with a constrained nominal subtype, Constraint_Error may be raised at the point of the call if it is determined while elaborating a return_subtype_indication or evaluating a return expression within the function that the value of the result will violate the constraint of this object's subtype.
AARM NOTE: Without such a permission, it would be very difficult
to implement "build-in-place" semantics. Such an exception is not handleable within the function, because in the nonlimited case, the constraint check to verify that the result satisfies the constraints of the object being initialized happens after the function returns, and we want the semantics to change as little as possible when switching between limited and nonlimited. This implies further that upon detecting such a situation, the implementation may need to simulate a goto to a point outside any local exception handlers prior to raising the exception.
TBD: Should we allow this for nonlimited result types as well?
Change 7.6.1(3/2):
... except in the case of a master: the execution of a body other than a package_body; the elaboration of a declaration other than the declaration of a package {or of a type}; the execution of an accept_statement, a block_statement, ...
Add at end of 7.6.1(13/2):
Add after 9.2(4):
For task objects whose outermost enclosing object is neither a declared object nor an object created by an allocator, activations are initiated after completing any initialization for this outermost enclosing object, prior to performing any other operation on the object. For a task that is created and returned as the result of a function call, activation does not occur until after the function returns.
AARM NOTE:
The intent is that "temporary" objects with task parts are treated similarly to an object created by an allocator. The "whole" object is initialized, and then all of the task parts are activated together. Each such "whole" object has its own task activation sequence, involving the activating task being suspended until all the new tasks complete their activation.
!discussion
(See proposal.)
!example
(See umm, er...imagine one here. - ED)
--!corrigendum 02.09(2)
!ACATS test
!appendix

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

Questions? Ask the ACAA Technical Agent