September 2000
This document was prepared by AXE Consulting under contract from The MITRE Corporation.
© 2000, The MITRE Corporation. All Rights Reserved.
This document may be copied, in whole or in part, in any form or by any means, as is, or with alterations, provided that (1) alterations are clearly marked as alterations and (2) this copyright notice is included unmodified in any copy. Any other use or distribution of this document is prohibited without the prior express permission of MITRE.
You use this document on the condition that you indemnify and hold harmless MITRE, its Board of Trustees, officers, agents, and employees, from any and all liability or damages to yourself or your hardware or software, or third parties, including attorneys' fees, court costs, and other related costs and expenses, arising out of your use of this document irrespective of the cause of said liability.
MITRE MAKES THIS DOCUMENT AVAILABLE ON AN "AS IS" BASIS AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE ACCURACY, CAPABILITY, EFFICIENCY MERCHANTABILITY, OR FUNCTIONING OF THIS DOCUMENT. IN NO EVENT WILL MITRE BE LIABLE FOR ANY GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL, EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF MITRE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
This document contains defect reports on the Ada 95 standard [ISO/IEC 8652:1995], and responses formulated by the Ada Rapporteur Group (ARG) of ISO/IEC JTC 1/SC 22/WG 9, the Ada working group. The ARG is the language maintenance subgroup of WG 9, meaning that it is responsible for determining the corrections to the standard.
Defect Reports usually come from comments submitted by the public to the ARG. These comments are distilled into a question, given in the Question section of the Defect Report response.
In order to formulate the response to the Defect Report, the question is carefully considered and often discussed at length by the ARG. The results are recorded in the Discussion section of the response. The answer to the question arrived at after the discussions is summarized in the Summary of Response section. A more detailed answer to the question can be found in the Response section. Sometimes, the issue is so obvious that there is no Response or Discussion section. If the result of the discussion finds that some change to the standard would be required to arrive at an answer to the question, a Corrigendum Wording section includes the specific wording change to standard. These Corrigendum Wording sections are gathered together in a Technical Corrigendum document.
A Defect Report and Response is the final step of a lengthy process of formulation, discussion, and approval. The working documents of the ARG (called Ada Issues) contain additional information about the issue and its resolution. Ada Issues may include sections for testing information (ACATS test), informal wording changes (Wording), and an appendix including E-Mail comments on this issue (Appendix). These sections are not included in the Defect Reports found in this document. This information is available in the Ada Issues documents, which can be accessed on the web at www.ada-auth.org/~acats/arg.
The Defect Reports and Responses contain many references of the form ss.cc(pp) or ss.cc.aa(pp). These refer to particular paragraphs in the standard, with the notation referencing the (sub)clause number in the Ada 95 standard (ss.cc.aa), followed by a parenthesized paragraph number (pp). Paragraphs are numbered by counting from the top of the (sub)clause, ignoring headings.
The Defect Reports and Responses contain references to the Annotated Ada Reference Manual (AARM). This document contains all of the text in the Ada 95 standard along with various annotations. It was prepared by the Ada 95 design team, and is intended primarily for compiler writers, test writers, and the ARG. The annotations include rationale for some rules. The AARM is often used by the ARG to determine the intent of the language designers.
The Defect Reports and Responses may contain references to Ada 83. Ada 83 is the common name for the previous version of the Ada standard, ISO/IEC 8652:1987. Similarly, AI83 refers to interpretations of that standard.
This document contains all of the Defect Reports used to prepare Ada Technical Corrigendum 1. Issues which did not result in wording changes to the standard are available in the companion document, Defect Reports Part 2. Resolutions of newer issues can be found on the web site mentioned previously.
This document is designed to be viewed with the default font as some Roman font, similar to the Ada 95 standard. This may require some adjustments to your browser.
2.1(8-9) say:
The letters allowed in identifiers are then restricted to lower_case_identifier_letters and upper_case_identifier_letters.
The version of 10646-1:1993 referred to in 1.2(8) names codes C6 and E6 as "Latin Capital Ligature AE" and "Latin Small Ligature AE".
This seems to imply that these characters are not allowed in identifiers. Are these characters allowed in identifiers? (Yes.)
The characters LATIN CAPITAL LETTER AE and LATIN SMALL LETTER AE are allowed in identifiers.
Replace 1.2(8):
ISO/IEC 10646-1:1993, Information technology -- Universal Multiple-Octet Coded Character Set (UCS) -- Part 1: Architecture and Basic Multilingual Plane.
by:
ISO/IEC 10646-1:1993, Information technology -- Universal Multiple-Octet Coded Character Set (UCS) -- Part 1: Architecture and Basic Multilingual Plane, supplemented by Technical Corrigendum 1:1996.
Technical Corrigendum 1 of 10646 names these characters LATIN CAPITAL LETTER AE and LATIN SMALL LETTER AE. The intent was that these letters be allowed in identifiers.
When does the elaboration of a subtype indication with a per-object constraint occur? What are the actions of such an elaboration?
When a component has a subtype_indication with a per-object constraint and an object of the type containing the component is declared, the subtype_indication containing the per-object constraint is apparently never elaborated.
3.8(18) explains that subtype_indications with per-object constraints are not elaborated, but that any expressions that are not part of a per-object expression are evaluated. However, what to do with the results of those evaluations never seems to be explained.
3.3.1(15-20) describes the process of elaborating an object_declaration. In step 3, per-object expressions are evaluated, but there is no mention of elaborating anything, although later paragraph 20 does seem to imply that some sort of elaborations were supposed to have taken place in step 3.
The elaboration of per-object constraints is mentioned in (at least) the following other places where objects are created:
According to a strict reading, elaborating the per-object constraint would appear to involve reevaluating the non-per-object expressions (since there doesn't seem to be any separate definition of what happens when a per-object constraint is elaborated), but not include any subtype compatibility checks that would normally occur as part of subtype elaboration (since elaboration of the subtype_indication containing the constraint isn't mentioned in these paragraphs). What are the intended semantics?
The elaboration of a subtype indication with a per-object constraint occurs when an object of the enclosing type is created. This elaboration consists of the evaluation of each per-object expression of the constraint, followed by the usual actions associated with such elaboration, but using the values for any expressions that are not part of a per-object expression that were determined earlier when the type definition was elaborated.
For evaluating a named association applying to multiple components in a per-object discriminant constraint, if the expression of the association is not part of a per-object expression, then it must be evaluated once for each associated component.
Replace 3.3.1(18):
by:
Replace 3.6(22):
The elaboration of a discrete_subtype_definition creates the discrete subtype, and consists of the elaboration of the subtype_indication or the evaluation of the range. The elaboration of a component_definition in an array_type_definition consists of the elaboration of the subtype_indication. The elaboration of any discrete_subtype_definitions and the elaboration of the component_definition are performed in an arbitrary order.
by:
The elaboration of a discrete_subtype_definition that does not contain any per-object expressions creates the discrete subtype, and consists of the elaboration of the subtype_indication or the evaluation of the range. The elaboration of a discrete_subtype_definition that contains one or more per-object expressions is defined in 3.8. The elaboration of a component_definition in an array_type_definition consists of the elaboration of the subtype_indication. The elaboration of any discrete_subtype_definitions and the elaboration of the component_definition are performed in an arbitrary order.
Replace 3.8(18):
Within the definition of a composite type, if a component_definition or discrete_subtype_definition (see 9.5.2) includes a name that denotes a discriminant of the type, or that is an attribute_reference whose prefix denotes the current instance of the type, the expression containing the name is called a per-object expression, and the constraint being defined is called a per-object constraint. For the elaboration of a component_definition of a component_declaration, if the constraint of the subtype_indication is not a per-object constraint, then the subtype_indication is elaborated. On the other hand, if the constraint is a per-object constraint, then the elaboration consists of the evaluation of any included expression that is not part of a per-object expression.
by:
Within the definition of a composite type, if a component_definition or discrete_subtype_definition (see 9.5.2) includes a name that denotes a discriminant of the type, or that is an attribute_reference whose prefix denotes the current instance of the type, the expression containing the name is called a per-object expression, and the constraint or range being defined is called a per-object constraint. For the elaboration of a component_definition of a component_declaration or the discrete_subtype_definition of an entry_declaration for an entry family (see 9.5.2), if the constraint or range of the subtype_indication or discrete_subtype_definition is not a per-object constraint, then the subtype_indication or discrete_subtype_definition is elaborated. On the other hand, if the constraint or range is a per-object constraint, then the elaboration consists of the evaluation of any included expression that is not part of a per-object expression. Each such expression is evaluated once unless it is part of a named association in a discriminant constraint, in which case it is evaluated once for each associated discriminant.
When a per-object constraint is elaborated (as part of creating an object), each per-object expression of the constraint is evaluated. For other expressions, the values determined during the elaboration of the component_definition or entry_declaration are used. Any checks associated with the enclosing subtype_indication or discrete_subtype_definition are performed, including the subtype compatibility check (see 3.2.2), and the associated subtype is created.
Replace 4.8(10):
by:
Replace 9.5.2(22):
For the elaboration of an entry_declaration for an entry family, if the discrete_subtype_definition contains no per-object expressions (see 3.8), then the discrete_subtype_definition is elaborated. Otherwise, the elaboration of the entry_declaration consists of the evaluation of any expression of the discrete_subtype_definition that is not a per-object expression (or part of one). The elaboration of an entry_declaration for a single entry has no effect.
by:
The elaboration of an entry_declaration for an entry family consists of the elaboration of the discrete_subtype_definition, as described in 3.8. The elaboration of an entry_declaration for a single entry has no effect.
Notwithstanding the rules given in 3.3.1(18), 4.3.1(19), and 4.8(10), the elaboration of the subtype indication of a component definition with a per-object constraint occurs when an object of the enclosing type is created. This elaboration takes place on elaboration of an object declaration, evaluation of an uninitialized allocator, and when evaluating an aggregate of the type.
The elaboration consists of the evaluation of each per-object expression of the component's constraint, followed by the conversion of the value of each expression of the constraint to its appropriate expected type and the performance of the compatibility check defined for the elaboration of the subtype indication (see 3.2.2(11)). The values used for any expressions that are not part of per-object expressions of the subtype's constraint are those determined during the original elaboration of the component definition as defined in 3.8(18). Such expressions are not reevaluated during elaboration of the per-object constraint that occurs as part of object creation, despite any rules that state when a per-object constraint is elaborated (e.g., as part of evaluating an allocator or aggregate).
Note further that the evaluation of expressions in a per-object constraint defined in 3.8(18) was intended to take into account the case of named associations for multiple components in a discriminant constraint. For such an association, the expression must be evaluated once for each associated component, as prescribed by 3.7.1(12).
There are two basic problems with the current wording of the standard regarding the elaboration of components with a per-object constraint. The first is that the rules don't explain what is done with the values obtained from expressions that are not part of per-object expressions (as defined in 3.8(18)) or whether such expression are reevaluated when a per-object constraint is later elaborated during object creation. The other problem is that the mention of elaboration of per-object constraints in rules such as 4.3.1(19) and 4.8(10) fails to cover the need for the subtype compatibility check that is normally performed when elaborating a subtype indication.
The intent was clearly that the values of the expressions evaluated as part of elaborating a component definition with a per-object constraint (3.8(18)) should be used later when creating an object of the containing type. It would not make sense to discard the values already determined and to reevaluate the expressions (especially if they have side effects). The description in the rules for allocator and aggregate evaluation that states that a per-object constraint is elaborated should mention that only the per-object expressions are evaluated at that point and that the values for other expressions are those determined earlier when the type was elaborated. (The description of the semantics of elaborating per-object constraints should really be centralized in a single place, such as 3.8(18).)
The rules for object declarations, allocator evaluation, and aggregate evaluation all fail to require the subtype compatibility check that occurs when a subtype indication is elaborated (and for object declarations even the constraint elaboration is omitted). This check is certainly needed in these cases as well. The fix for this oversight is to define each of these rules to include the elaboration of the subtype indications for components with per-object constraints (which also subsumes the elaboration of the constraint itself).
One other minor gap is that the case of elaborating a named discriminant association within a per-object constraint is not covered by that rule in 3.8(18). The rule as given only describes a single evaluation for each expression of the constraint, but the intent is that for a named association the expression should be evaluated for each associated component.
How should an implementation on a one's complement machine implement modular types intended to use all the bits of a full word?
Implementation Permission: On a one's complement machine, the implementation may support non-binary moduli above System.Max_Nonbinary_Modulus.
Insert after 3.5.4(27):
For a one's complement machine, the high bound of the base range of a modular type whose modulus is one less than a power of 2 may be equal to the modulus, rather than one less than the modulus. It is implementation defined for which powers of 2, if any, this permission is exercised.
the new paragraph:
For a one's complement machine, implementations may support non-binary modulus values greater than System.Max_Nonbinary_Modulus. It is implementation defined which specific values greater than System.Max_Nonbinary_Modulus, if any, are supported.
Consider a 36-bit one's complement machine. One should be able to declare a 36-bit modular type. For logical operations to make sense, the all-ones bit pattern ought to be allowed, and should compare not equal to zero, and greater than every other bit pattern. The Implementation Permission in 3.5.4(27) is intended to allow this.
On a 36-bit two's complement machine, one would declare:
type T is mod 2**36;
and T'Modulus would be 2**36, and the base range of T would be 0..2**36-1. If one says:
type TT is mod 2**36-1;
TT'Modulus is 2**36-1, and the base range of TT is usually 0..2**36-2. The implementation permission says that the base range of TT can be 0..2**36-1. This means that the all-ones bit pattern is a valid value of the type, and is not reduced via the modulus.
The relationship given in 3.5.8(2) in the case of T'Machine_Radix = 10 implies that S'Digits + 1 = T'Model_Mantissa in such a case. Is this correct? (No.)
The relationship between S'Digits and T'Model_Mantissa given in 3.5.8(2) states that S'Digits is the largest value of d for which
This allows for a "guard digit" which is necessary to take care of extreme circumstances that arise if the Machine_Radix is not decimal (as is usually the case).
However, this guard digit is unnecessary if Machine_Radix is 10 or a power of 10 and in such a case the relationship should read
If Machine_Radix is 10 this becomes simply
so that S'Digits = T'Model_Mantissa.
Replace 3.5.8(2):
by:
This question echoes back to a change made between 1980 preliminary Ada and the 1983 standard which is worth explaining as background.
In Ada 83, the user specified a number D of decimal digits and the implementation then provided model numbers using B binary digits. Intuitively one might expect to need log 10 / log 2 (3.3219...) binary digits for every decimal digit (with appropriate rounding up). The 1980 edition of the Ada Reference Manual (3.5.7 third paragraph) says
So 1 decimal digit might be expected to be equivalent to 4 binary digits, 2 decimal digits equivalent to 7 binary digits and so on. But this is not enough. Four binary digits give a relative precision of between 1 in 8 and 1 in 16 whereas one decimal digit requests a maximum precision of 1 in 10. Thus there are places where the model numbers for B = 4 are slightly too far apart.
For example the decimal model numbers around 10000 for D = 1 are
whereas the binary model numbers for B = 4 are
and 8192 and 9216 are more than 1000 apart.
This surprising behaviour resulted in the addition of one to the formula so that 3.5.7(6) of Ada 83 concludes
In Ada 95 this formula has been generalized to use T'Machine_Radix rather than 2. However, the special case where Machine_Radix is 10 (or indeed a power of 10) has been overlooked since then no anomalous situations can arise and the "guard digit" is not required.
The formula should therefore be adjusted accordingly.
Note the peculiar phenomenon that more digits may be required for a hexadecimal machine than a decimal machine. Thus one decimal digit requires 2 hexadecimal digits.
3.5.9(8) says, "For a type defined by an ordinary_fixed_point_definition (an ordinary fixed point type), the small may be specified by an attribute_definition_clause (see 13.3)".
3.5.10(2) says, "Small may be specified for nonderived fixed point types via an attribute_definition_clause (see 13.3)".
13.3(5) says, "An attribute_designator is allowed in an attribute_definition_clause only if this International Standard explicitly allows it".
What is the intent? May Small be specified for a derived fixed point type? (No.) May it be specified for a decimal type? (No.)
A Small clause is illegal for a decimal fixed point type. A Small clause is illegal for a derived fixed point type.
Replace 3.5.10(2):
by:
A Small clause is illegal for a decimal fixed point type. A Small clause is illegal for a derived fixed point type.
The intent was to disallow a Small clause for a decimal type, because the Small is determined by the type declaration.
The intent was to also disallow a Small clause for a derived fixed point type, because otherwise the model numbers of the parent and derived types might differ, resulting in semantic difficulties.
Shouldn't the word "prefix" be in the sans serif font? (Yes.)
The word "prefix" should be in the sans serif font.
Replace 3.6.2(2):
The following attributes are defined for a prefix A that is of an array type (after any implicit dereference), or denotes a constrained array subtype:
by:
The following attributes are defined for a prefix A that is of an array type (after any implicit dereference), or denotes a constrained array subtype:
This was an editing error.
12.5(10) (a NOTE) says that "A discriminant_part is allowed only for certain kinds of types, and therefore only for certain kinds of generic formal types. See 3.7."
Unfortunately, the rule in 3.7(8) only applies to known_discriminant_parts. 3.7 does not contain any rule restricting the usage of unknown_discriminant_parts.
Various syntax rules usually do the job, but for generic formal types, the syntax allows unknown_discriminant_parts. Therefore, are the following legal? (No.)
generic type Disc (<>) is (<>); -- Illegal! type Flt (<>) is digits (<>); -- Illegal! type Str (<>) is new String; -- Illegal! procedure ....
A generic formal type must not have an unknown_discriminant_part, unless the type is a composite non-array type.
Replace 3.7(8):
A known_discriminant_part is only permitted in a declaration for a composite type that is not an array type (this includes generic formal types); a type declared with a known_discriminant_part is called a discriminated type, as is a type that inherits (known) discriminants.
by:
A discriminant_part is only permitted in a declaration for a composite type that is not an array type (this includes generic formal types). A type declared with a known_discriminant_part is called a discriminated type, as is a type that inherits (known) discriminants.
The intent is that elementary and array types cannot have discriminant parts (known or unknown).
Consider the following code fragment:
package P is pragma Elaborate_Body; type T is private; A : constant T; private type T (D : Integer := 0) is null record; type Ptr is access all T; A : constant T := (D => 1); end P;
with P; package Q is type A1 is array (1 .. 10) of aliased P.T; type A2 is array (1 .. 10) of P.T; X : A1; end Q;
with P, Q; procedure R is procedure S (Y : in out Q.A2) is begin Y (1) := P.A; end; begin S (Q.A2 (Q.X)); -- This call will change the discriminant of Q.X (1) end;
This example illustrates a case where it is possible to change the discriminant of an aliased component of an object, which is supposed to be forbidden.
A view conversion of an array object is illegal if the target subtype and the operand do not have both aliased components or both non-aliased components.
A discriminant constraint for a general access type is illegal if there are places where the designated subtype appears constrained and others where it appears unconstrained.
Replace 3.7.1(7):
A discriminant_constraint is only allowed in a subtype_indication whose subtype_mark denotes either an unconstrained discriminated subtype, or an unconstrained access subtype whose designated subtype is an unconstrained discriminated subtype.
by:
A discriminant_constraint is only allowed in a subtype_indication whose subtype_mark denotes either an unconstrained discriminated subtype, or an unconstrained access subtype whose designated subtype is an unconstrained discriminated subtype. However, in the case of a general access subtype, a discriminant_constraint is illegal if there is a place within the immediate scope of the designated subtype where the designated subtype's view is constrained.
Replace 4.6(11):
by:
Replace 4.6(12):
by:
The problem (1) comes from the fact that it is possible to use a view conversion to convert an array object with aliased components to an array type with non-aliased components. Such a conversion must be disallowed.
The ARG also discussed the following example, which illustrates another case where the standard seems to allow a discriminant to be changed:
with Q; package body P is PT : Ptr (0) := Q.X (1)'access; begin Q.X := (others => (D => 2)); -- Changes the discriminant of Q.X (2) end P;
The root of problem (2) is that there are places (e.g., the visible part of P) where P.T is constrained, but other places (e.g., the private part and body of P) where P.T is unconstrained. This causes privacy problems when applying the following rule:
"if a component_definition contains the reserved word aliased and the type of the component is discriminated, then the nominal subtype of the component shall be constrained." (3.6(11))
Also note that the problem exists with non-private types, provided that the characteristic that the type is unconstrained is not visible everywhere:
package P.C is type NT is new T; private type Ptr is access all NT; -- Causes the same problems as P.Ptr. end P.C;
One way to fix this problem would be to require a component-by-component check on the assignment to Q.X, but that would be very expensive. Moreover, a compile-time check would clearly be better than a run-time check.
Aliasedness of the components is not really what is causing trouble, though. It is really the existence of a general access type, and in fact of a discriminant constraint on such an access type, which causes trouble. Thus, forbidding such a constraint is the chosen solution, especially considering that constraints on access types are not a terribly useful feature.
13.1(10) seems to forbid the following example:
with Ada.Streams; use Ada.Streams; generic type T is private; package Attr_Rep is type NT is new T; procedure Attribute_Write( Stream : access Root_Stream_Type'Class; Item : in NT); for NT'Write use Attribute_Write; -- Illegal? (No.) end Attr_Rep;
13.1(10) says:
This rule does not apply to an attribute_definition_clause for one of the stream-oriented attributes Read, Write, Input, and Output.
Replace 3.8(5):
component_item ::= component_declaration | representation_clause
by:
component_item ::= component_declaration | aspect_clause
Replace 3.11(4):
basic_declarative_item ::=
basic_declaration | representation_clause | use_clause
by:
basic_declarative_item ::=
basic_declaration | aspect_clause | use_clause
Replace 9.1(5):
task_item ::= entry_declaration | representation_clause
by:
task_item ::= entry_declaration | aspect_clause
Replace 9.1(12):
As part of the initialization of a task object, any representation_clauses and any per-object constraints associated with entry_declarations of the corresponding task_definition are elaborated in the given order.
by:
As part of the initialization of a task object, any aspect_clauses and any per-object constraints associated with entry_declarations of the corresponding task_definition are elaborated in the given order.
Replace 9.4(5):
protected_operation_declaration ::= subprogram_declaration
| entry_declaration
| representation_clause
by:
protected_operation_declaration ::= subprogram_declaration
| entry_declaration
| aspect_clause
Replace 9.4(8):
protected_operation_item ::= subprogram_declaration
| subprogram_body
| entry_body
| representation_clause
by:
protected_operation_item ::= subprogram_declaration
| subprogram_body
| entry_body
| aspect_clause
Replace 13(1):
This section describes features for querying and controlling aspects of representation and for interfacing to hardware.
by:
This section describes features for querying and controlling certain aspects of entities and for interfacing to hardware.
Replace the title of 13.1:
Representation Items
by:
Operational and Representation Items
Replace 13.1(1):
There are three kinds of representation items: representation_clauses, component_clauses, and representation pragmas. Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware). Representation items also specify other specifiable properties of entities. A representation item applies to an entity identified by a local_name, which denotes an entity declared local to the current declarative region, or a library unit declared immediately preceding a representation pragma in a compilation.
by:
Representation and operational items can be used to specify aspects of entities. Two kinds of aspects of entities can be specified: aspects of representation and operational aspects. Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. Operational items specify other properties of entities.
There are six kinds of representation items: attribute_definition_clauses for representation attributes, enumeration_representation_clauses, record_representation_clauses, at_clauses, component_clauses, and representation pragmas. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware).
An operational item is an attribute_definition_clause for an operational attribute.
An operational item or a representation item applies to an entity identified by a local_name, which denotes an entity declared local to the current declarative region, or a library unit declared immediately preceding a representation pragma in a compilation.
Replace 13.1(2):
representation_clause ::= attribute_definition_clause
| enumeration_representation_clause
| record_representation_clause
| at_clause
by:
aspect_clause ::= attribute_definition_clause
| enumeration_representation_clause
| record_representation_clause
| at_clause
Replace 13.1(4):
by:
Replace 13.1(5):
In a representation item, if the local_name is a direct_name, then it shall resolve to denote a declaration (or, in the case of a pragma, one or more declarations) that occurs immediately within the same declarative_region as the representation item. If the local_name has an attribute_designator, then it shall resolve to denote an implementation-defined component (see 13.5.1) or a class-wide type implicitly declared immediately within the same declarative_region as the representation item. A local_name that is a library_unit_name (only permitted in a representation pragma) shall resolve to denote the library_item that immediately precedes (except for other pragmas) the representation pragma.
by:
In an operational item or representation item, if the local_name is a direct_name, then it shall resolve to denote a declaration (or, in the case of a pragma, one or more declarations) that occurs immediately within the same declarative_region as the item. If the local_name has an attribute_designator, then it shall resolve to denote an implementation-defined component (see 13.5.1) or a class-wide type implicitly declared immediately within the same declarative_region as the item. A local_name that is a library_unit_name (only permitted in a representation pragma) shall resolve to denote the library_item that immediately precedes (except for other pragmas) the representation pragma.
Replace 13.1(6):
The local_name of a representation_clause or representation pragma shall statically denote an entity (or, in the case of a pragma, one or more entities) declared immediately preceding it in a compilation, or within the same declarative_part, package_specification, task_definition, protected_definition, or record_definition as the representation item. If a local_name denotes a local callable entity, it may do so through a local subprogram_renaming_declaration (as a way to resolve ambiguity in the presence of overloading); otherwise, the local_name shall not denote a renaming_declaration.
by:
The local_name of an aspect_clause or representation pragma shall statically denote an entity (or, in the case of a pragma, one or more entities) declared immediately preceding it in a compilation, or within the same declarative_part, package_specification, task_definition, protected_definition, or record_definition as the representation or operational item. If a local_name denotes a local callable entity, it may do so through a local subprogram_renaming_declaration (as a way to resolve ambiguity in the presence of overloading); otherwise, the local_name shall not denote a renaming_declaration.
Insert after 13.1(8):
A representation item directly specifies an aspect of representation of the entity denoted by the local_name, except in the case of a type-related representation item, whose local_name shall denote a first subtype, and which directly specifies an aspect of the subtype's type. A representation item that names a subtype is either subtype-specific (Size and Alignment clauses) or type-related (all others). Subtype-specific aspects may differ for different subtypes of the same type.
the new paragraph:
An operational item directly specifies an operational aspect of the type of the subtype denoted by the local_name. The local_name of an operational item shall denote a first subtype. An operational item that names a subtype is type-related.
Insert after 13.1(9):
A representation item that directly specifies an aspect of a subtype or type shall appear after the type is completely defined (see 3.11.1), and before the subtype or type is frozen (see 13.14). If a representation item is given that directly specifies an aspect of an entity, then it is illegal to give another representation item that directly specifies the same aspect of the entity.
the new paragraph:
An operational item that directly specifies an aspect of a type shall appear before the type is frozen (see 13.14). If an operational item is given that directly specifies an aspect of a type, then it is illegal to give another operational item that directly specifies the same aspect of the type.
Replace 13.1(11):
Representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type.
by:
Operational and representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type.
Replace 13.1(13):
A representation item that is not supported by the implementation is illegal, or raises an exception at run time.
by:
A representation or operational item that is not supported by the implementation is illegal, or raises an exception at run time.
Replace 13.1(19):
For the elaboration of a representation_clause, any evaluable constructs within it are evaluated.
by:
For the elaboration of an aspect_clause, any evaluable constructs within it are evaluated.
Replace the title of 13.3:
Representation Attributes
by:
Operational and Representation Attributes
Replace 13.3(1):
The values of certain implementation-dependent characteristics can be obtained by interrogating appropriate representation attributes. Some of these attributes are specifiable via an attribute_definition_clause.
by:
The values of certain implementation-dependent characteristics can be obtained by interrogating appropriate operational or representation attributes. Some of these attributes are specifiable via an attribute_definition_clause.
Replace 13.3(5):
An attribute_designator is allowed in an attribute_definition_clause only if this International Standard explicitly allows it, or for an implementation-defined attribute if the implementation allows it. Each specifiable attribute constitutes an aspect of representation.
by:
An attribute_designator is allowed in an attribute_definition_clause only if this International Standard explicitly allows it, or for an implementation-defined attribute if the implementation allows it. Each specifiable attribute constitutes an operational aspect or an aspect of representation.
Replace 13.3(9):
The following attributes are defined:
by:
The following representation attributes are defined: Address, Alignment, Size, Storage_Size, and Component_Size.
Replace 13.3(74):
For every subtype S of a tagged type T (specific or class-wide), the following attribute is defined:
by:
The following operational attribute is defined: External_Tag.
For every subtype S of a tagged type T (specific or class-wide):
Replace 13.4(11):
by:
Replace 13.11(12):
For every access subtype S, the following attributes are defined:
by:
For every access subtype S, the following representation attributes are defined:
Replace 13.13.2(1):
The Write, Read, Output, and Input attributes convert values to a stream of elements and reconstruct values from a stream.
by:
The operational attributes Write, Read, Output, and Input convert values to a stream of elements and reconstruct values from a stream.
Replace 13.14(19):
A representation item that directly specifies an aspect of an entity shall appear before the entity is frozen (see 13.1).
by:
An operational item or a representation item that directly specifies an aspect of an entity shall appear before the entity is frozen (see 13.1).
The intent of 13.1(10) is to forbid two types from having different representation in certain cases. However, the stream-oriented attributes, although they are formally defined to be "representation attributes", do not actually affect the representation of the type. Therefore, there is no need for 13.1(10) to apply to these attributes. Furthermore, as the example illustrates, applying the rule to these attributes would seriously hinder their usefulness.
The definition of stream attributes as "representation attributes" has proven to be a continuing problem. Several issues have made it necessary to exempt stream attributes from the rules for representation attributes; indeed the number of such exemptions makes it clear that it is confusing to classify them as representation attributes. Therefore, we have taken the major step of defining a new kind of attribute, the "operational attributes", and redefining stream attributes to be of this kind.
In particular, 7.3(5), 13.1(10), and the last sentence of 13.1(11) are unchanged, so that these rules do not apply to operational items. None of these rules are necessary for these attributes. We've also left 3.8(11) unchanged, as an operational item cannot occur here. Changes to 13.1(15) and 13.1(18) are found in 8652/0040 (AI-00108).
Consider the following code fragment:
type T is tagged null record; procedure P(X : access T); Y : aliased T'Class := ...; type T_Ptr is access all T'Class; Z : T_Ptr;
P(Y'access); -- (1) Legal? (Yes.) P(new T'Class'(...)); -- (2) Legal? (Yes.) P(Z); -- (3) Legal.
The call at (3) is clearly legal, and is a dispatching call.
However, the call at (1) appears to be illegal. The expected type for Y'Access is the anonymous type "access T", by 6.4.1(3). 3.10.2(24) says, "If the designated type of A [here, A is the anonymous access type] is tagged, then the type of the view [Y] shall be covered by the designated type". The type of the view is T'Class, which is not covered by the designated type, which is T. Therefore, Y'Access is illegal here.
The call at (2) appears to be illegal for the same reason.
It would seem that the same rules should apply to all of these calls; (1) and (2) should be legal, and should be dispatching calls.
An attribute reference of the Access attribute may be used as the actual parameter in a dispatching call, if the formal is an access parameter designating a tagged type, and the prefix of the attribute reference is of the corresponding class-wide type. Such an actual is considered to be dynamically tagged.
An analogous rule applies to an attribute reference of Unchecked_Access and to an allocator.
Replace 3.9.2(7):
A type_conversion is statically or dynamically tagged according to whether the type determined by the subtype_mark is specific or class-wide, respectively. For a controlling operand that is designated by an actual parameter, the controlling operand is statically or dynamically tagged according to whether the designated type of the actual parameter is specific or class-wide, respectively.
by:
A type_conversion is statically or dynamically tagged according to whether the type determined by the subtype_mark is specific or class-wide, respectively. For an object that is designated by an expression whose expected type is an anonymous access-to-specific tagged type, the object is dynamically tagged if the expression, ignoring enclosing parentheses, is of the form X'Access, where X is of a class-wide type, or is of the form new T'(...), where T denotes a class-wide subtype. Otherwise, the object is statically or dynamically tagged according to whether the designated type of the type of the expression is specific or class-wide, respectively.
Replace 3.9.2(9):
If the expected type for an expression or name is some specific tagged type, then the expression or name shall not be dynamically tagged unless it is a controlling operand in a call on a dispatching operation. Similarly, if the expected type for an expression is an anonymous access-to-specific tagged type, then the expression shall not be of an access-to-class-wide type unless it designates a controlling operand in a call on a dispatching operation.
by:
If the expected type for an expression or name is some specific tagged type, then the expression or name shall not be dynamically tagged unless it is a controlling operand in a call on a dispatching operation. Similarly, if the expected type for an expression is an anonymous access-to-specific tagged type, then the object designated by the expression shall not be dynamically tagged unless it is a controlling operand in a call on a dispatching operation.
Replace 3.10.2(24):
by:
Replace 3.10.2(27):
by:
Replace 4.8(3):
The expected type for an allocator shall be a single access-to-object type whose designated type covers the type determined by the subtype_mark of the subtype_indication or qualified_expression.
by:
The expected type for an allocator shall be a single access-to-object type with designated type D such that either D covers the type determined by the subtype_mark of the subtype_indication or qualified_expression, or the expected type is anonymous and the determined type is D'Class.
The rules should be equivalent in these cases; anything else would be surprising to the programmer. This is achieved by the above wording.
In the call at (1), Y'Access is of the anonymous type "access T". Y'Access is dynamically tagged, despite the fact that its type's designated type is not class-wide.
In the call at (2), new T'Class'(...) is also of the anonymous type "access T", and is also dynamically tagged.
Thus, all three calls are legal, and are dispatching calls to P.
No wording changes are needed for Unchecked_Access, since it is already defined in terms of Access.
6.3.1(2-13) define the default convention of various entities (that is, the convention in the absence of a convention-specifying pragma):
-----------------
1. What is the default convention of an entity not covered by 6.3.1, such as a record type? (Ada.)
-----------------
2. Does an inherited or overriding subprogram have (by default) the same convention as the parent subprogram? (Yes.)
6.3.1(3) implies that if the calling convention of a parent subprogram is not Ada, the default convention of an overriding subprogram is, nonetheless, Ada. However, 3.9.2(10) says:
6.3.1(17) requires matching conventions for subtype conformance. Thus, the default calling convention for this overriding case is illegal; the programmer must give a pragma specifying the convention in this case. This seems unfriendly.
On the other hand, 3.4(18) says:
And 6.1(22) says:
These paragraphs seem to imply that an inherited subprogram inherits the calling convention of its parent, as part of the inherited profile.
-----------------
3. Is an implicitly declared dispatching "/=" operator legal? (Yes.)
Paragraph 3.9.1(1) says that the primitive subprograms of a tagged type are called dispatching operations. Paragraph 3.9.2(10) goes on to say that a dispatching operation shall not be of convention Intrinsic. However, paragraph 6.3.1(6) says that "/=" declared implicitly due to the declaration of "=" is of convention Intrinsic, by default.
Together these imply that the "/=" implicitly declared due to the declaration of "=" of a tagged type is an illegal dispatching operation. Is this the intent? (No.)
Unless specified otherwise in the standard, the default convention of any entity is Ada.
An inherited or overriding subprogram of a type extension inherits the calling convention of the parent subprogram.
New operations of type extensions have the convention of their type unless a new convention is defined for the operation, if this is supported by an implementation.
The convention of the partial view of a private type or private extension is the convention of the full type.
An explicitly declared dispatching operation shall not have convention Intrinsic. However, an implicitly declared dispatching "/=" operator with Boolean result legally has convention Intrinsic.
Replace 3.9.2(10):
In the declaration of a dispatching operation of a tagged type, everywhere a subtype of the tagged type appears as a subtype of the profile (see 6.1), it shall statically match the first subtype of the tagged type. If the dispatching operation overrides an inherited subprogram, it shall be subtype conformant with the inherited subprogram. A dispatching operation shall not be of convention Intrinsic. If a dispatching operation overrides the predefined equals operator, then it shall be of convention Ada (either explicitly or by default -- see 6.3.1).
by:
In the declaration of a dispatching operation of a tagged type, everywhere a subtype of the tagged type appears as a subtype of the profile (see 6.1), it shall statically match the first subtype of the tagged type. If the dispatching operation overrides an inherited subprogram, it shall be subtype conformant with the inherited subprogram. The convention of an inherited or overriding dispatching operation is the convention of the corresponding primitive operation of the parent type. An explicitly declared dispatching operation shall not be of convention Intrinsic.
Replace 6.3.1(2):
As explained in B.1, ``Interfacing Pragmas'', a convention can be specified for an entity. For a callable entity or access-to-subprogram type, the convention is called the calling convention. The following conventions are defined by the language:
by:
As explained in B.1, ``Interfacing Pragmas'', a convention can be specified for an entity. Unless this International Standard states otherwise, the default convention of an entity is Ada. For a callable entity or access-to-subprogram type, the convention is called the calling convention. The following calling conventions are defined by the language:
Insert after 6.3.1(13):
the new paragraph:
Replace 13.1(11):
Representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type.
by:
Representation aspects of a generic formal parameter are the same as those of the actual. Representation aspects of a partial view are the same as those of the full view. A type-related representation item is not allowed for a descendant of a generic formal untagged type.
1. The default convention ought to be Ada for any entity not covered by 6.3.1. The dispatching operations of a type ought to inherit the convention of the type, for convenient interfacing to other OOP languages. (See below for more discussion of this point.)
-----------------
2. It is important that Ada allow clean interfaces to other programming languages. In particular, it is important that Ada's tagged types can be used to interface to other OOP languages.
If an Ada implementation is tightly integrated with another language, such as C++ or Java, it is nice if an Ada tagged type can be declared as an extension of a (foreign) type (or class) of the other language. Presumably, all of the dispatching operations of this foreign type would be defined as imported, with the convention of that other language. When defining the type extension in Ada, it would be very inconvenient if every overriding needed a pragma Convention on it to match that of the inherited operation, as required by 3.9.2(10).
Hence, it seems appropriate to define the default calling convention of an overriding of an inherited dispatching operation to be the same as that of the corresponding operation on the parent type, rather than always being convention "Ada" as specified in 6.3.1(3).
For example:
package Java.Graphics is type Graphics_Obj is tagged limited private; procedure drawString(G : in out Graphics_Obj; S : String); pragma Import(Java, drawString); ... end Java.Graphics;
with Java.Graphics; use Java.Graphics; package Flight_Simulator is type Simulator_Obj is new Graphics_Obj with private; procedure drawString(S : in out Simulator_Obj; S : String); -- implicit: pragma Convention(Java, drawString); ... end Flight_Simulator;
The "pragma Convention(Java, ...);" should be implicit when overriding a dispatching operation with convention Java. Anything else would be illegal by 3.9.2(10), and it seems silly to require the programmer to litter their program with redundant "pragma Convention"s.
The Note B.1(42) - derived from 13.1 - implies permission of implementation-defined restrictions of interfacing pragmas. Hence an implementation will be allowed to reject the attempt to create "heterogeneous" tagged types, i.e., types having primitive operations of different, explicitly specified conventions or of explicitly specified conventions different from the convention of the type.
2.a. The "Breach of Privacy" Issue
Presently, the convention of a primitive subprogram can be specified in the private part of the declaring package. The current rules require explicit confirmation of this convention for overriding subprograms and thus constitute a breach of the privacy of the private part, since the user needs to know about this privately specified convention in order to make the overriding declaration legal.
We are very reluctant to mandate Convention pragmas in the visible part of the package. Although such a rule might be derivable from freezing rules, it nevertheless could create a compatibility problem for existing code.
The proposed new rule of inheriting the convention eases, but does not eliminate, the breach of privacy, as any explicitly specified convention will still need to confirm the inherited convention.
At the implementation level, both the existing and the proposed model breach the private part, as subtype conformance of overriding with inherited subprograms includes checking for equality of the convention.
2.b. Deriving the convention of operations from the type
Having dispatching operations with the convention of some other OOP language, while the type is not represented according to the convention of this other language, will be almost impossible to implement. The "normal" case will be that both type and operations need the convention pragma. In this context, it makes little sense that the convention of primitive operations defaults to Ada rather than to the convention of their type. The user will be forced to repeat the pragma for all the operations of the type. Considerably more convenient is a model, in which the default convention of dispatching operations is inherited from the type, but overridable if the implementation allows for such mixed conventions.
Since current rules imply that the convention of a type needs to be specified for the full view of the type, such dependency creates yet another breach of privacy in the case of private tagged types. However, the breach already exists as explained in 2.a. and then to exploit it for more convenience to the user and a cleaner overall model seems justified.
Mandating the specification of the convention for the partial view in order to avoid the breach of privacy seems too much of an incompatibility for existing code.
2.c. The convention of a partial view
As mentioned previously, the current rules of the standard require that the convention be specified on the full view. So, what is the convention of a partial view? It is clear that a partial view and full view must have the same representation (including convention), since they are just views of the same entity. However, while this is obvious, it is also not mentioned in the standard. A statement to this effect needs to be added to 13.1.
-----------------
3. Clearly, an implicitly declared dispatching "/=" should not automatically be illegal.
The proposed new wording precludes declaring a dispatching operation by renaming the Intrinsic "/=", which is good (since there is no real body associated with "/="). It does not make "/=" itself illegal, which is also good.
The reason for 6.3.1(4-10) making various subprograms Intrinsic is that these subprograms don't really exist in machine code. For example, an implementation would typically not generate any code for the implicitly-declared "/=" operator -- instead, it would call the "=" operator, and then do a "not" operation at the call site. We don't want to allow 'Access of such subprograms, because it would introduce an implementation burden -- the implementation would have to materialize these subprograms as real machine-code subprograms, which is not otherwise necessary.
A similar issue arises with 6.3.1, which says that an inherited subprogram of a generic formal type with unknown discriminants is of convention Intrinsic, by default.
The reason for this rule is obscure enough that it should have been documented in the AARM: Consider:
package P is type Root is tagged null record; procedure Proc(X: Root); end P;
generic type Formal(<>) is new Root with private; package G is ... end G;
package body G is ... X: Formal := ...; ... Proc(X); -- This is a dispatching call in Instance, because -- the actual type for Formal is class-wide. ... -- Proc'Access would be illegal here, because it is of -- convention Intrinsic, by 6.3.1(8). end G;
type Actual is new Root with ...; procedure Proc(X: Actual); package Instance is new G(Formal => Actual'Class); -- It is legal to pass in a class-wide actual, because Formal -- has unknown discriminants.
Within Instance, all calls to Proc will be dispatching calls, so Proc doesn't really exist in machine code, so we wish to avoid taking 'Access of it. 6.3.1(8) applies to those cases where the actual type might be class-wide, and makes these Intrinsic, thus forbidding 'Access.
The wording change to 3.9.2(10) shown above means that it is permitted to have such an inherited subprogram. If the specification of G contained a type extension of Formal, then that type's inherited Proc would also have convention Intrinsic, which would be legal. However, an explicit overriding of that Proc would be illegal.
NOTE 3.4(31) says, "If the parent type is an access type, then the parent and the derived type share the same storage pool..." This is clearly what we want, but I can't seem to prove it from the real rules (i.e. non-NOTES).
A derived access type shares its parent's storage pool.
Replace 3.10(7):
There are two kinds of access types, access-to-object types, whose values designate objects, and access-to-subprogram types, whose values designate subprograms. Associated with an access-to-object type is a storage pool; several access types may share the same storage pool. A storage pool is an area of storage used to hold dynamically allocated objects (called pool elements) created by allocators; storage pools are described further in 13.11, ``Storage Management''.
by:
There are two kinds of access types, access-to-object types, whose values designate objects, and access-to-subprogram types, whose values designate subprograms. Associated with an access-to-object type is a storage pool; several access types may share the same storage pool. All descendants of an access type share the same storage pool. A storage pool is an area of storage used to hold dynamically allocated objects (called pool elements) created by allocators; storage pools are described further in 13.11, ``Storage Management''.
A derived access type shares its parent's storage pool.
NOTE 3.4(31) makes the intent clear.
Furthermore, 13.11.2(16) says, "The execution of a call to an instance of Unchecked_Deallocation is erroneous if the object was created other than by an allocator for an access type whose pool is Name'Storage_Pool."
Thus, if a derived access type does not have the same pool as its parent, then the following would be erroneous:
type Parent is access Integer; type Derived is new Parent; X: Derived := new Integer; Y: Parent := Parent(X); procedure Free is new Unchecked_Deallocation(Object => Integer, Name => Parent); ... Free(Y);
The above was not erroneous in Ada 83. This would be a serious upward incompatibility, which there was no intention to introduce.
Note that no such upward incompatibility is documented in the AARM.
3.10(14) says:
However, access_type_definition includes access_to_object_definition. What is the intent?
The second sentence of 3.10(14) applies to all access-to-object types, including those defined by access_definitions.
Replace 3.10(14):
All subtypes of an access-to-subprogram type are constrained. The first subtype of a type defined by an access_type_definition or an access_to_object_definition is unconstrained if the designated subtype is an unconstrained array or discriminated type; otherwise it is constrained.
by:
All subtypes of an access-to-subprogram type are constrained. The first subtype of a type defined by an access_definition or an access_to_object_definition is unconstrained if the designated subtype is an unconstrained array or discriminated subtype; otherwise it is constrained.
The notion of designated subtype doesn't make sense for access-to-subprograms. The intent is that this rule should apply to all access-to-object types. Apparently, access_type_definition is a "typo".
Another typo was noted in this paragraph. The paragraph says "...if the designated subtype is an unconstrained array or discriminated type...", but this clearly should say "...discriminated {sub}type...".
3.11(10) indicates that an elaboration check is required only when a subprogram has an explicit body that is a subprogram_body. However, when a renaming declaration is used as a body, it is possible for the elaboration of the renaming declaration to require the evaluation of a name, such as X.all, that implies some sort of elaboration check should be performed. For example:
function F return Integer; type Pointer_To_Func is access function return Integer;
X : Pointer_To_Func := Q'access; -- Presume Q already elaborated
Y : Integer := F; -- We need some sort of elaboration check
....
Z : Pointer_To_Func := X;
function F return Integer renames Z.all;
In the above, clearly we need to wait until the expression "Z.all" is evaluated before F can be safely called. However, it is not clear that any check for this is required by 3.11(10).
By the way, where is "body" defined? It presumably includes entry body, and perhaps renaming-as-body. However, only the syntactic entity BODY is defined (in 3.11). Where is the unbolded term "body" defined?
An elaboration check is performed for a call to a subprogram whose body is given as a renaming-as-body. This check fails if the renaming-as-body has not yet been elaborated. (As usual, an elaboration check is also performed for the renamed subprogram, and fails if its body has not yet been elaborated.)
Replace 3.11(10):
by:
Replace 3.11.1(1):
Declarations sometimes come in two parts. A declaration that requires a second part is said to require completion. The second part is called the completion of the declaration (and of the entity declared), and is either another declaration, a body, or a pragma.
by:
Declarations sometimes come in two parts. A declaration that requires a second part is said to require completion. The second part is called the completion of the declaration (and of the entity declared), and is either another declaration, a body, or a pragma. A body is a body, an entry_body, or a renaming-as-body (see 8.5.4).
Insert before 8.5.4(8):
For a call on a renaming of a dispatching subprogram that is overridden, if the overriding occurred before the renaming, then the body executed is that of the overriding declaration, even if the overriding declaration is not visible at the place of the renaming; otherwise, the inherited or predefined subprogram is called.
the new paragraph:
For a call to a subprogram whose body is given as a renaming-as-body, the execution of the renaming-as-body is equivalent to the execution of a subprogram_body that simply calls the renamed subprogram with its formal parameters as the actual parameters and, if it is a function, returns the value of the call.
Replace 13.14(3):
The end of a declarative_part, protected_body, or a declaration of a library package or generic library package, causes freezing of each entity declared within it, except for incomplete types. A noninstance body causes freezing of each entity declared before it within the same declarative_part.
by:
The end of a declarative_part, protected_body, or a declaration of a library package or generic library package, causes freezing of each entity declared within it, except for incomplete types. A noninstance body other than a renaming-as-body causes freezing of each entity declared before it within the same declarative_part.
Since the elaboration of a renaming-as-body may evaluate expressions, it is clearly necessary that this elaboration be performed before calling the subprogram. Therefore, an elaboration check should be done on a subprogram whose body is a renaming-as-body, not just when the body is a subprogram_body.
It seems that the right model for renaming-as-body that occurs after the subprogram is frozen should be that of a wrapper subprogram, with its own elaboration flag.
Taken together, these rules imply that when calling a subprogram whose body is a renaming-as-body, a check will be made that the renaming-as-body has been elaborated, and also that the body of the renamed subprogram has been elaborated. Furthermore, if the renamed subprogram is in turn completed by another renaming-as-body, the body of that third subprogram will also be checked; the rule is transitive.
See 8652/0027 (AI-00135) for a discussion of circularities involving renamings-as-body.
This issue also adds the missing definition of the semantic term "body". This change makes a renaming-as-body a body. However, doing so triggers the freezing rule 13.14(3): "A noninstance body other than a renaming-as-body causes freezing of each entity declared before it within the same declarative_part." It clearly was the intent of the designers of the language that renaming-as-body not freeze (otherwise the second sentence of 8.5.4(5) could never be true), and existing compilers do not freeze when a renaming-as-body is encountered. We do not want to change this behavior, so we add an exception to 13.14(3).
Paragraph 4.1.4(12) says:
AARM J(1.d) lists several Ada 83 floating-point attributes that have been removed from the language, including 'Small; AARM J(1.h), however, says that "Implementations can continue to support the above features for upward compatibility".
Since 'Small is a language-defined attribute for fixed-point types, 4.1.4(12) implies that an implementation must not provide a 'Small attribute for floating-point types. This clearly contradicts the intent of J(1).
May an implementation support the 'Small attribute for floating-point types? (Yes.)
An implementation may support an implementation-defined attribute Small for floating point types.
Replace 4.1.4(12):
An implementation may provide implementation-defined attributes; the identifier for an implementation-defined attribute shall differ from those of the language-defined attributes.
by:
An implementation may provide implementation-defined attributes; the identifier for an implementation-defined attribute shall differ from those of the language-defined attributes unless supplied for compatibility with a previous edition of this International Standard.
The intent is that implementations be allowed to support all Ada 83 attributes, for upward compatibility. Thus, it is important that they be allowed to support the Small attribute on floating point types. Therefore, this resolution makes a specific exception to the rule in 4.1.4(12).
The following language-defined types are private, and have an explicitly defined primitive "=" operator:
This would seem to imply that the composability of these "=" operators depends on whether the implementation chooses to implement them as tagged types, by 4.5.2(14-15):
and by 4.5.2(21-24):
This would cause portability problems.
Also, in the above definition, what does "in terms of" mean? For a composite type, if some parts have an "=" with side effects, does the language define whether all of these side effects happen, and in what order?
The primitive equality operators of a language-defined type compose properly (i.e., do not "reemerge"), when the type is used as a component type, or a generic actual type.
For any composite type, the order in which "=" is called for components is not defined by the language. Furthermore, if the result can be determined before calling "=" on some components, the language does not define whether "=" is called on those components.
Insert after 4.5.2(24):
the new paragraph:
For any composite type, the order in which "=" is called for components is unspecified. Furthermore, if the result can be determined before calling "=" on some components, it is unspecified whether "=" is called on those components.
Insert after 4.5.2(32):
A membership test using not in gives the complementary result to the corresponding membership test using in.
the new paragraph:
Implementation Requirements
For all nonlimited types declared in language-defined packages, the "="
and "/=" operators of the type shall behave as if they were the predefined
equality operators for the purposes of the equality of composite types and
generic formal types.
Composability of equality for a type T means three things:
Non-composability means that the predefined equality is called for T, despite the fact that T has a user-defined equality operator. Of course, if there is no user-defined equality, then equality always composes properly.
Item 3 is irrelevant here, since none of the types in question is (visibly) tagged.
For a private type, if the underlying type is tagged, or if there is no user-defined equality, then equality composes. Otherwise, it does not. (Here, "underlying type" means the full type, or if that comes from a private type, then the underlying type of that type, and so on.)
However, for the private types mentioned in the question, the standard does not specify whether the underlying type is tagged, nor whether the equality operator is truly user-defined (as opposed to just being the normal bit-wise equality).
It is important that the composability of "=" for these types be defined by the language. We choose to make them composable. An implementation can achieve this by making the full type tagged. Alternatively, the implementation could simply use the predefined "=" for these types. (Alternatively, an implementation could treat these types specially, making them untagged, but with composable equality. However, this would add some complexity to the compiler.)
Here is an analysis of implementation concerns for each type in question:
As to the second question, the standard clearly does not define any order of calling "=" on components, nor does it say whether the results are combined with "and" or "and then". Equality operators with side effects are questionable in any case, so we allow implementations freedom to do what is most convenient and/or most efficient. Consider equality of a variant record: The implementation might first check that the discriminants are equal, and if not, skip the component-by-component comparison. Alternatively, the implementation might first compare the common elements, and then check the discriminants. A third possibility is to first compare some portions with a bit-wise equality, and then (conditionally) call user-defined equality operators on the other components. All of these implementations are valid.
The definiteness of a type is not preserved by type derivation. A type with defaulted discriminants may be derived from a type without defaulted discriminants and vice-versa.
This makes it possible to rename a component of a record that later disappears due to an assignment to the enclosing object, as shown in the following examples:
1 - An example where the parent type is indefinite and the derived type is definite:
type T1 (D1 : Boolean) is record case D1 is when False => C1 : Integer; when True => C2 : Float; end case; end record;
generic type F is new T1; X : in out F; package G is C1_Ren : Integer renames X.C1; end G;
type T2 (D2 : Boolean := True) is new T1 (D1 => D2);
Y : T2;
package I is new G (T2, Y);
Y := (D1 => True, C2 => 3.0); -- Oops! What happened to I.C1_Ren
The declaration of C1_Ren in the generic G is legal as per 8.5.1(5), because the formal type F is indefinite. But when G is instantiated with type T2, the actual type is definite, so now we have renamed a component that may disappear by assignment to the variable Y. Note that the declaration of C1_Ren might be in the body of G, so we cannot avoid this problem by rechecking 8.5.1(5) on the instantiation.
2 - An example where the parent type is definite and the derived type is indefinite:
type Definite_Parent (D1 : Integer := 6) is record F : String (1 .. D1); end record;
type Indefinite_Child (D2 : Integer) is new Definite_Parent (D1 => D2);
Y : Definite_Parent;
procedure P (X : in out Indefinite_Child) is C : Character renames X.F (3); begin X := (0, ""); -- X.F (3) has disappeared! end; begin P (Indefinite_Child (Y));
Assume that the implementation chooses to pass X by reference. Then, 6.4.1(10) says that there is an implicit view conversion to Indefinite_Child, and the formal parameter X then denotes the result of this view conversion. The result of the explicit view conversion is unconstrained, and the result of the implicit view conversion is also unconstrained, hence X is unconstrained, which violates the language design principle of the NOTE in 3.7(28).
One of the unpleasant consequences of this violation is that the assignment to X doesn't raise an exception, and after the execution of this assignment C denotes a non-existent component.
Note that if the implementation chooses to pass by copy, then there is an implicit value conversion -- see 6.4.1(11). So in that case, there's no problem.
The legality rules about object renaming are checked in the private part of an instance. In a generic body, they are checked in an assume-the-worst manner: it is illegal to rename a component that depends on a discriminant of a variable whose nominal subtype is an untagged indefinite generic formal derived type (or a descendant of such a type) unless the variable is aliased.
A view conversion to an indefinite object is constrained.
For a conversion of an object name to a tagged type to be a view conversion, the object's nominal subtype has to be tagged.
Replace 4.6(5):
A type_conversion whose operand is the name of an object is called a view conversion if its target type is tagged, or if it appears as an actual parameter of mode out or in out; other type_conversions are called value conversions.
by:
A type_conversion whose operand is the name of an object is called a view conversion if both its target type and operand type are tagged, or if it appears as an actual parameter of mode out or in out; other type_conversions are called value conversions.
Replace 4.6(54):
by:
Replace 8.5.1(5):
The renamed entity shall not be a subcomponent that depends on discriminants of a variable whose nominal subtype is unconstrained, unless this subtype is indefinite, or the variable is aliased. A slice of an array shall not be renamed if this restriction disallows renaming of the array.
by:
The renamed entity shall not be a subcomponent that depends on discriminants of a variable whose nominal subtype is unconstrained, unless this subtype is indefinite, or the variable is aliased. A slice of an array shall not be renamed if this restriction disallows renaming of the array. In addition to the places where Legality Rules normally apply, these rules apply also in the private part of an instance of a generic unit. These rules also apply for a renaming that appears in the body of a generic unit, with the additional requirement that even if the nominal subtype of the variable is indefinite, its type shall not be a descendant of an untagged generic formal derived type.
The fix for example 1 is to forbid the renaming: even though the formal type looks indefinite, it is possible for the actual type to be definite. Note that the manual already covers the case where C1_Ren is declared in the visible part of the generic unit, because legality rules are checked in the instance (12.3(11)). We are extending the legality rules for object renaming to apply in the private part of the instance, and we are assuming the worst in the body.
To fix example 2, we could forbid a view conversion that obtains an indefinite view of an object whose nominal subtype is definite. However, such a view conversion was legal in Ada 83, so this would be an incompatibility. It seems better to mandate a check on the assignment to X: it is very surprising that this check is not there in the first place.
Also consider the following example:
package P is pragma Elaborate_Body; type T (D : Integer) is private; private type T (D : Integer) is tagged record C : String (1 .. D); end record; end P;
with P; package Q is type NT (ND : Integer := 3) is new T (ND); X : NT; Y : NT (0); end Q
with Q; package body P is C_Ren : Character renames T (Q.X).C (2); begin Q.X := Q.Y; -- Houston, we have a problem! end P;
This is similar to example 2 above, except that here we don't use a view conversion to change the discriminant of Q.X. In this case the trouble comes from the view conversion T (Q.X) in the declaration of C_Ren. As long as all the types involved are tagged, renaming a component of a view conversion works fine, because tagged types don't have defaulted discriminants. But here we go through an untagged type to change the discriminants. It is clear that the conversion T (Q.X) should not be considered a view conversion.
Is Integer'Succ fully conformant with Integer'Pred? (No.)
From 6.3.1(19-22), it would appear so: both attribute_references have the syntactic construction
For two attribute_references to fully conform, the attribute_designator must be the same.
Insert after 6.3.1(21):
the new paragraph:
It would be ludicrous to treat two different attributes to be fully conformant. None of the reasons for conformance checking would be enforced if this were true. Thus, the standard's failure to require this can only be categorized as an oversight.
Is the rule given in 7.3.1(6) intended to apply to cases where a derived type is declared outside the declarative region in which its parent type is immediately declared? (No.)
Consider the following example:
package body R is
package P is type Pt is ...; private procedure Op (X : Pt); end P;
type T is new P.Pt; -- procedure Op (X : T); is inherited here but not yet declared
package body P is -- procedure Op (X : T) is declared here, according to -- 7.3.1(6), because the corresponding declaration for Pt -- is visible at this point and the body of P is still within -- the immediate scope of T. It is somewhat strange, however, -- that the subprogram does not get declared immediately -- within the same declarative region as T. -- Is this the intent? (No.) begin Op(T'(...)); -- Legal? (No.) end P;
end R;