!standard 3.10 (09) 02-06-07 AI95-00225/04 !class binding interpretation 99-12-09 !status Amendment 200Y 02-05-14 !status ARG Approved 8-0-0 01-10-07 !status work item 99-12-09 !status received 99-12-09 !qualifier Clarification !priority Medium !difficulty Medium !subject Aliased current instance for limited types !summary The current instance of a type is aliased if and only if: The type is tagged and limited; or The type has the reserved word limited in its full definition. !question The attributes Access and Unchecked_Access are allowed only on aliased objects, "including possibly the current instance of a limited type within its definition", in the words of the standard (3.10.2(24/1)). But the standard never says where the type is limited. There are types that can become nonlimited later in their immediate scope, because the full type of a component turns out to be nonlimited. There are also cases where in a generic package a type looks limited, but from outside a particular instance, the type looks nonlimited, because the "formally" limited components were not "actually" limited. Is it intended that the legality of Access and Unchecked_Access depends on the ultimate limitedness of the type? (No.) If not, what is the intent? (See summary.) !recommendation (See summary.) !wording (See summary.) !discussion The crux of the problem is that a type can become non-limited at some arbitrary later point in its scope. This makes implementing this rule problematical. One solution is to make the check when an object is declared. While this works, it goes against the Ada 95 design principle of detecting errors as soon as possible. Another possibility is to make the check at the freezing point of the type. While more information is known at this point, it still is possible for the type to become non-limited later (if a component type becomes non-limited, for instance). So this is not sufficient, some checking still has to be deferred. The difficulty of making the check raises the question as to whether this complex check is helpful to Ada users. Since it is unclear if a type is limited, users may be confused as to whether 'Access is allowed. This is not helpful. Therefore, we adopt the easily understood rule, either the type is limited tagged (in which case the limitedness can't change) or the type was explicitly declared with the reserved word limited (and again it cannot become non-limited). This will eliminate confusion and simplify the job of compilers. This rule has the nice property that only types that are return-by-reference have an aliased current instance. That's good, because if they are not return-by-reference, (and not controlled), then the object is allowed to be copied and moved around as part of a function return, which would render the use of the Access attribute meaningless. It is true that this new rule could break existing code. But existing compilers seem to make this check in different ways, which means that code is not portable. And any such code is rather pathological, as it could break if the type is returned from a function. !ACATS test A test should be constructed for these cases, or a new subtest added to one of the existing tests (B3A2015, B3A0004, B3A0001). !corrigendum 3.10(09) @drepl A view of an object is defined to be @i if it is defined by an @fa or @fa with the reserved word @b, or by a renaming of an aliased view. In addition, the dereference of an access-to-object value denotes an aliased view, as does a view conversion (see 4.6) of an aliased view. Finally, the current instance of a limited type, and a formal parameter or generic formal object of a tagged type are defined to be aliased. Aliased views are the ones that can be designated by an access value. If the view defined by an @fa is aliased, and the type of the object has discriminants, then the object is constrained; if its nominal subtype is unconstrained, then the object is constrained by its initial value. Similarly, if the object created by an @fa has discriminants, the object is constrained, either by the designated subtype, or by its initial value. @dby A view of an object is defined to be @i if it is defined by an @fa or @fa with the reserved word @b, or by a renaming of an aliased view. In addition, the dereference of an access-to-object value denotes an aliased view, as does a view conversion (see 4.6) of an aliased view. A current instance of a limited tagged type, a protected type, a task type, or a type that has the reserved word @b in its full definition is also defined to be aliased. Finally, a formal parameter or generic formal object of a tagged type is defined to be aliased. Aliased views are the ones that can be designated by an access value. If the view defined by an @fa is aliased, and the type of the object has discriminants, then the object is constrained; if its nominal subtype is unconstrained, then the object is constrained by its initial value. Similarly, if the object created by an @fa has discriminants, the object is constrained, either by the designated subtype, or by its initial value. !appendix From: Tucker Taft Sent: Wednesday, December 01, 1999 4:17 PM Thanks to a posting on comp.lang.ada, I learned that our front end was not enforcing a rule that only limited record types should allow the use of T'Access or T'Unchecked_Access inside the type, because only a limited type has an aliased "current instance." In my attempt to add an enforcement for this rule, I ran into a nasty situation. When do you decide whether a type is truly "limited"? There are types that can become nonlimited later in their immediate scope, because the full type of a component turns out to be nonlimited. There are also cases where in a generic package a spec a type looks limited, but from outside a particular instance, the type looks nonlimited, because the "formally" limited components were not "actually" limited. Ultimately, I implemented a bit of a half-baked check. When encountering the T'Access or T'Unchecked_Access during the initial processing of a record type, if the type *might* be limited then we allow it. Later, when an individual object is created which causes the T'Access or T'Unchecked_Access to be evaluated, if the type is not limited at that point, we complain. This is clearly less than desirable. To decide whether a record type "might" be limited, I use the following information: 1) if it is tagged, then it can only be limited if the ultimate ancestor (aka "root") type had the word "limited" in its definition. 2) if it is the completion of a private type, then it can only be limited if the partial view was limited. This leaves most untagged record types being considered "might be limited" because when we encounter the T'[Unchecked_]Access, we might not have seen all of the components (we haven't seen the ones that come later in the record than the one with the use of T'Access), and one of the components might turn out to be limited, rendering the whole record limited. Of course, we could implement the check in a second pass, or set a flag indicating that we saw a T'Access somewhere, but then as mentioned above, the limitedness might disappear later anyway. This all seems pretty unsavory, and makes me want to suggest that the rule should be that you may only use T'[Unchecked_]Access inside an untagged record type if it explicitly uses the word "limited" in its definition. This has the nice characteristic that only types that are return-by-reference have an aliased current instance. That's good, because if they are not return-by-reference, (and not controlled), then the object is allowed to be copied and moved around as part of a function return, which would render the use of T'[Unchecked_]Access pretty meaningless. The net effect of this is that certain programs would require the addition of the word "limited" on a record type definition, if there is a use of T'[Unchecked_]Access somewhere inside the record type definition. Note that *tagged* types already effectively have this rule. Another nice feature of this rule is that the use of T'Unchecked_Access would have the same requirement as the rule for access discriminants (3.7(10)) which requires the explicit use of "limited." These two rules are clearly related, and should share the same kind of "limitedness" requirement. The basic problem with the 3.10(9) rule as written now is that the "limited"ness of a type can disappear if you don't use "limited" explicitly, when you learn more about one of the components. This makes correct enforcement much more difficult, and seems to provide no benefit to the programmer. Comments? ************************************************************* From: Ed Schonberg Sent: Thursday, December 02, 1999 9:34 PM > Thanks to a posting on comp.lang.ada, I learned that our front end > was not enforcing a rule that only limited record types should allow > the use of T'Access or T'Unchecked_Access inside the type, because > only a limited type has an aliased "current instance." Interesting, I just went through the same exercise, not doubt motivated by a report from the same source... > In my attempt to add an enforcement for this rule, I ran into > a nasty situation. When do you decide whether a type is truly "limited"? It would seem that the place at which the type is frozen is a good place. At least this is where we do it. It appears that no further information about the components should matter after that point. Is this semantically incorrect? In GNAT this choice also means that we don't apply the check to a type defined in a generic unit, only to the corresponding type in an instance. Again, are were deviating from the intent? In any case, it means that while processing the record declaration we accept the 'Access conditiona- lly, and have to make a separate pass over the declaration at the freezing point (it has to be done anyway to freeze the component types). > .. the rule should be that you may only use T'[Unchecked_]Access > inside an untagged record type if it explicitly uses the > word "limited" in its definition. This has the nice characteristic > that only types that are return-by-reference have an aliased > current instance. That's good, because if they are not return-by-reference, > (and not controlled), then the object is allowed to be copied and moved > around as part of a function return, which would render the use > of T'[Unchecked_]Access pretty meaningless. > > The net effect of this is that certain programs would require > the addition of the word "limited" on a record type definition, > if there is a use of T'[Unchecked_]Access somewhere inside > the record type definition. Note that *tagged* types already > effectively have this rule. > > Another nice feature of this rule is that the use of T'Unchecked_Access > would have the same requirement as the rule for access > discriminants (3.7(10)) which requires the explicit use of > "limited." These two rules are clearly related, and should > share the same kind of "limitedness" requirement. > The basic problem with the 3.10(9) rule as written now is that the > "limited"ness of a type can disappear if you don't use "limited" > explicitly, when you learn more about one of the components. > This makes correct enforcement much more difficult, and seems to > provide no benefit to the programmer. I agree that there is no particular benefit to the current rule, the keyword should be required, the programmer has to know that the type is limited, he might as well say so! Ed Schonberg ************************************************************* From: Pascal Leroy Sent: Friday, December 03, 1999 4:24 AM > > In my attempt to add an enforcement for this rule, I ran into > > a nasty situation. When do you decide whether a type is truly "limited"? > > It would seem that the place at which the type is frozen is a good place. Performing this type of check at the freezing point is possible, but I find it distasteful, as it tends to break privateness and the linear compilation model. Surely at the freezing point you know the completion of all the types involved, but it can be the case that a type becomes nonlimited _after_ its freezing point. So you need to either (1) assume-the-worst or (2) determine if there will be a point in the future where the type becomes nonlimited. If you choose (1), I don't see much benefit in delaying the check until the freezing point; if you choose (2) the check becomes rather complicated and can have counter-intuitive consequences (eg the absence/presence of a body influencing the legality of T'Access). > > .. the rule should be that you may only use T'[Unchecked_]Access > > inside an untagged record type if it explicitly uses the > > word "limited" in its definition. I agree, that's the right way to fix this problem. It can break existing code, but that's rather pathological code, and it's not portable anyway because different compilers seem to do different things today. ************************************************************* From: Randy Brukardt In writing up this AI, I borrowed wording from RM 7.5(4), rather than using Tucker's "explicitly includes". *************************************************************