CVS difference for ais/ai-00279.txt
--- ais/ai-00279.txt 2004/02/07 01:11:23 1.7
+++ ais/ai-00279.txt 2004/09/10 00:43:33 1.8
@@ -1,4 +1,4 @@
-!standard 13.13.02 (34) 04-02-06 AI95-00279/04
+!standard 13.13.02 (34) 04-09-08 AI95-00279/05
!standard 3.09 (12)
!standard 13.13.02 (36/1)
!standard 13.14 (19/1)
@@ -11,8 +11,9 @@
!subject Tag read by T'Class'Input
-If Ada.Tags.Internal_Tag is given a string identifying a library-level type in
-which has not yet been frozen, Tag_Error is raised.
+If Ada.Tags.Internal_Tag or Ada.Tags.Descendant_Tag is given a string
+identifying a library-level type in which has not yet been frozen, Tag_Error
If the tag identified by T'Class'Input identifies a type:
-- that is the tag of some type not covered by T'Class, Constraint_Error
@@ -25,10 +26,10 @@
-T'Class'Input reads in a string, maps it to a tag by calling Tags.Internal_Tag,
-and dispatches accordingly.
+T'Class'Input reads in a string, maps it to a tag by calling
+Tags.Descendant_Tag, and dispatches accordingly.
-What happens if the call to Tags.Internal_Tag yields either
+What happens if the call to Tags.Descendant_Tag yields either
a) the tag of some type not covered by T'Class
b) the tag of an abstract type
@@ -43,7 +44,8 @@
-Add to 3.9(12):
+Add to 3.9(12) and 3.9(12.1) (the first paragraph of the insertion from
Tag_Error is also raised if the specific type identified is a library-level
type whose tag has not yet been elaborated.
@@ -58,12 +60,12 @@
If the internal tag provided to T'Class'Input identifies a specific type whose
-freezing point has not been elaborated, or does not exist in the partition at
-the time of the call, execution is erroneous.
+tag has not been elaborated, or does not exist in the partition at the time of
+the call, execution is erroneous.
-The definition of Internal_Tag prevents such a tag from being provided to
+The definition of Descendant_Tag prevents such a tag from being provided to
T'Class'Input if T is a library-level type. However, this is needed for nested
tagged types and potentially for user-provided 'Tag_Read routines.
@@ -75,16 +77,22 @@
-The exact wording of 13.13.2(34) is "...dispatches to the subprogram denoted
+This AI assumes that AI-344 is approved and included in the Amendment.
+Version /04 contains the appropriate wording if AI-344 is not included
+in the Amendment.
+The exact wording of 13.13.2(34/2) is "...dispatches to the subprogram denoted
by the Input attribute of the specific type identified by the internal tag;
returns that result.". Reading this strictly, we would expect the appropriate
'Input to be called (by dispatching), followed by a conversion to the return
type. That is, somewhere this is code like:
- return T'Class(Call_by_Tag (Tags.Internal_Tag(...), 'Input(Stream));
+ return T'Class(Dispatching_Constructor (Tags.Descendant_Tag(...),
-(where Call_by_Tag is a magic routine that dispatches to the appropriate
-routine identified by the tag in its first parameter).
+(where Dispatching_Constructor is a magic routine that dispatches to the
+appropriate routine identified by the tag in its first parameter; AI-260-2
+proposes to standardize such a routine).
If the tag dispatched on is not covered by T, then this final conversion
would raise Constraint_Error. Therefore, we simply confirm the existing
@@ -116,37 +124,63 @@
flow analysis, or completely avoiding T'Class'Input. Luckily, we can mitigate
-The problem is really that Internal_Tag is returning the tag for a type that
-is not frozen or does not currently exist. If Internal_Tag is implemented
+The problem is really that Descendant_Tag is returning the tag for a type that
+is not frozen or does not currently exist. If Descendant_Tag is implemented
dynamically, this cannot happen (such a type must necessarily raise Tag_Error).
-However, if Internal_Tag is implemented statically (as allowed by the standard),
-this can happen.
+However, if Descendant_Tag is implemented partially statically, this can happen.
-We can mandate that Internal_Tag behave as if tags are allocated dynamically.
+We can mandate that Descendant_Tag behave as if tags are allocated dynamically.
For a static implementation, this only requires a Boolean value associated with
-each tag; For Internal_Tag, if the value is False for the appropriate tag,
+each tag; For Descendant_Tag, if the value is False for the appropriate tag,
Tag_Error is raised, otherwise the tag is returned. However, this approach
runs into problem with nested tagged types, which may be elaborated by multiple
tasks at the same time. In this case, a single Boolean does not work.
-However, nested tagged types are exceedingly rare. We do not lose much by not
-covering them. Therefore, we define that a tag is elaborated at the freezing
-point of the tagged type, and then adopt the rule that Internal_Tag must raise
-Tag_Error if the string identifies a library-level type whose tag
+AI-344 allows type extensions that are more nested than the original type.
+The AI also defines that the tag is sufficient to distiguish the descendant
+from all other descendants of the same type (even if they are from different
+elaborations of the same type declaration). This implies that Descendant_Tag
+will have at least some dynamic characteristics; a fully static implementation
+would be incorrect. This means that we could insist on checks for any types
+that have a library-level ancestor.
+However, nested tagged types of all kinds can be "de-elaborated" as well as
+elaborated. That would complicate the rule. Moreover, AI-344 is careful not
+to require implementation changes for nested tagged types not extended from
+some less-nested ancestor. Therefore, they could still be implemented with
+a static scheme, where making the check is impossible due to race conditions
+and multiple elaborations. Finally, AI-344 does not require Descendant_Tag to
+be able to tell between instances of the same type. Thus, it still would be
+possible to read the tag and it confuse with some other instance of the type
+(if the prefix type to T'Class'Input is more nested than some ancestor).
+The primary purpose of the Tag_Error rule for Ada.Tags is to insure that a
+static analysis of a program (without control flow information) can prove that
+there are no erroneous uses of T'Class'Input. For this purpose, requiring
+checks for library-level types is sufficient. If the user insures that all
+calls to T'Class'Input have a library-level type as the prefix, then no
+erroneousness can occur: either the tag has been elaborated, or Tag_Error is
+raised if the tag is prematurely read. If the tag of a more nested descendant
+type is read, Descendant_Tag is defined to raise Tag_Error (whether or not the
+type exists currently). This can be checked by a static analysis tool without
+the need to simulate control flows.
+Therefore, we define that a tag is elaborated at the freezing
+point of the tagged type, and then adopt the rule that Descendant_Tag must
+raise Tag_Error if the string identifies a library-level type whose tag
has not been elaborated. This rule allows a single Boolean value to be
-used, and does not have any race conditions.
+used in a static implementation, and does not have any race conditions.
-With this rule, the erroneous case can only occur for nested tagged types (that
-is, a tagged type not declared at the library-level). For any library-level
-type, either the type has been frozen and exists normally, or Tag_Error is
-raised if the tag is prematurely read. This means that we can verify that a
-program does not contain T'Class'Input erroneousness simply by verifying that
-there are no nested tagged types (a virtual certainty).
+The Internal_Tag function also has this rule, as it eliminate erroneousness
+from user-written routines (including instances of
+Generic_Dispatching_Constructor, see AI-260-2) and as there is no additional
The wording for erroneous execution includes "does not exist" so that a type
which existed earlier but now does not exist is covered. Such a type can only
-be a problem if it is derived from a type which now exists (presumably just
-below the call to T'Class'Input).
+be a problem if it is derived from a type which now exists and is at the
+same nesting level (it presumably is declared just below the call to
We considered simplifying the check to make it easier to implement. The
@@ -171,12 +205,21 @@
external tag, or raises Tag_Error if the given string is not the external tag
for any specific type of the partition.
-The function Internal_Tag returns the tag that corresponds to the given
+The function Internal_Tag returns a tag that corresponds to the given
external tag, or raises Tag_Error if the given string is not the external tag
for any specific type of the partition. Tag_Error is also raised if the
specific type identified is a library-level type whose tag has not
yet been elaborated.
+The function Descendant_Tag returns the (internal) tag for the type
+that corresponds to the given external tag and is both a descendant of the
+type identified by the Ancestor tag and has the same accessibility level as
+the identified ancestor. Tag_Error is raised if External is not the
+external tag for such a type. Tag_Error is also raised if the
+specific type identified is a library-level type whose tag has not
+yet been elaborated.
@@ -187,11 +230,12 @@
@xindent<First reads the external tag from @i<Stream> and determines the
-corresponding internal tag (by calling Tags.Internal_Tag(String'Input(@i<Stream>))
--- ches to the subprogram denoted by the Input
-attribute of the specific type identified by the internal tag; returns that
-result. If the specific type identified by the internal tag is not covered by
-T'Class or is abstract, Constraint_Error is raised.>
+corresponding internal tag (by calling
+Tags.Descendant_Tag(String'Input(@i<Stream>, @i<S>'Tag)) -- see 3.9) and then
+dispatches to the subprogram denoted by the Input attribute of the specific
+type identified by the internal tag; returns that result. If the specific type
+identified by the internal tag is not covered by T'Class or is abstract,
+Constraint_Error is raised.>
Questions? Ask the ACAA Technical Agent