ms-4.6 ADA 9X SNAPSHOT OF MAPPING SPECIFICATION PRIOR TO REVISION Version 4.6 21 May 1992 IR-MA-1250-3 Ada 9X Mapping/Revision Team Intermetrics, Inc. 733 Concord Avenue Cambridge, Massachusetts 02138 (617)661-1840 Published by Intermetrics, Inc. 733 Concord Avenue Cambridge, Massachusetts 02138 Copyright (C) 1992 Intermetrics, Inc. This report has been produced under the sponsorship of the Ada 9X Project Office under contract F08635-90-C-0066. It is provided for the Ada 9X Volunteer Reviewers to show our current progress in addressing the recommendations of the recent ISO WG9 and Ada 9X DR meetings. This document has not undergone the full quality control process, and should be considered a working draft. This document may be reproduced provided it is accompanied by this paragraph. Please see the Reader's Guide (Chapter 0) for more information. Acknowledgements This document was prepared by the Ada 9X Mapping/Revision Team based at Intermetrics, Inc. The members of the team are: W. Carlson, Program Manager; T. Taft, Technical Director; R. Duff (Oak Tree Software); M. Edwards; C. Garrity; R. Hilliard; O. Pazy; D. Rosenfeld; L. Shafer; W. White. The following consultants to the Ada 9X Project have contributed to the Specialized Needs Annexes: T. Baker (Real-Time/Systems-Programming -- SEI, FSU); B. Brosgol (Information-Systems -- Consultant); K. Dritz (Numerics -- Argonne National Laboratory); A. Gargaro (Distribution -- Computer Sciences); J. Goodenough (Real-Time/Systems-Programming -- SEI); J. McHugh (Safety-Critical -- Consultant); B. Wichmann (Safety-Critical -- NPL: UK). This work is continuously being reviewed by the Ada 9X Distinguished Reviewers: E. Ploedereder, Chairman (Tartan); B. Bardin (Hughes); B. Brett (DEC); B. Brosgol (Consultant); N. Cohen (IBM); R. Dewar (NYU); G. Dismukes (Telesoft); A. Evans (Consultant); A. Gargaro (Computer Sciences); M. Gerhardt (ESL); J. Goodenough (SEI); T. Harrison (ISSI); S. Heilbrunner (University of Salzburg: Austria); P. Hilfinger (UC/Berkeley); J. Ichbiah (Consultant: DR emeritus); M. Kamrad II (Paramax Systems); P. Kruchten (Rational); R. Landwehr (CCI: Germany); C. Lester (Portsmouth Polytechnic: UK); D. Luckham (Stanford); L. Mansson (TELIA Research: Sweden); R. Mathis (Consultant); S. Michell (Multiprocessor Toolsmiths: Canada); M. Mills (US Air Force); D. Pogge (US Navy); K. Power (Boeing); O. Roubine (Verdix: France); W. Taylor (Consultant: UK); E. Vasilescu (Grumman). Other valuable feedback influencing the revision process is also continuously being received from the Ada 9X Language Precision Team (Odyssey Research Associates), the Ada 9X User/Implementor Teams (AETECH, Tartan, Telesoft), the Ada 9X Implementation Analysis Team (New York University) and the Ada community-at-large. The Ada 9X Project is sponsored by the Ada Joint Program Office. Christine M. Anderson at the Air Force Wright Laboratory, Armament Directorate, is the project manager. Table of Contents (Note: This document is not paginated; a page corresponds to roughly 150 lines) 0. Reader's Guide to the Ada 9X Mapping Specification Snapshot 3-1 3. Ada 9X Declarations and Types 3-1 3.1. Declarations 3-1 3.2. Objects and Named Numbers 3-1 3.2.1. Object Declarations 3-1 3.2.2. Number Declarations 3-1 3.3. Types and Subtypes 3-1 3.3.1. Type Declarations 3-1 3.3.2. Subtype Declarations 3-2 3.3.3. Classification of Operations 3-2 3.4. Derived Types 3-2 3.4.1. Tagged Types and Type Extensions [new] 3-2 3.4.2. Operations of Tagged Types [new] 3-3 3.5. Scalar Types 3-3 3.5.1. Enumeration Types 3-3 3.5.2. Character Types 3-3 3.5.3. Boolean Types 3-3 3.5.4. Integer Types 3-3 3.5.5. Operations of Discrete Types 3-4 3.5.6. Real Types 3-4 3.5.7. Floating Point Types 3-4 3.5.8. Operations of Floating Point Types 3-4 3.5.9. Fixed Point Types 3-4 3.5.10. Operations of Fixed Point Types 3-4 3.6. Composite Types [new] 3-4 3.6.1. Discriminants [originally RM 3.7.1] 3-4 3.6.2. Discriminant Constraints [originally RM 3.7.2] 3-4 3.7. Array Types [originally RM 3.6] 3-5 3.7.1. Index Constraints and Discrete Ranges [originally RM 3-5 3.6.1] 3.7.2. Operations of Array Types [originally RM 3.6.2] 3-5 3.7.3. String Types [originally RM 3.6.3] 3-5 3.8. Record Types [originally RM 3.7] 3-5 3.8.1. Variant Parts [originally RM 3.7.3] 3-5 3.8.2. Record Extension [new] 3-5 3.8.3. Operations of Record Types [originally RM 3.7.4] 3-5 3.9. Access Types [originally 3.8] 3-5 3.9.1. Incomplete Type Declarations [originally 3.8.1] 3-5 3.9.2. Operations of Access Types [originally 3.8.2] 3-5 3.10. Declarative Parts [originally 3.9] 4-1 4. Ada 9X Names and Expressions 4-1 4.1. Names 4-1 4.1.1. Indexed Components 4-1 4.1.2. Slices 4-1 4.1.3. Selected Components 4-1 4.1.4. Attributes 4-1 4.2. Literals 4-1 4.3. Aggregates 4-1 4.3.1. Record Aggregates 4-1 4.3.2. Array Aggregates 4-1 4.4. Expressions 4-1 4.5. Operators and Expression Evaluation 4-1 4.5.1. Logical Operators and Short-circuit Control Forms 4-1 4.5.2. Relational Operators and Membership Tests 4-1 4.5.3. Binary Adding Operators 4-1 4.5.4. Unary Adding Operators 4-1 4.5.5. Multiplying Operators 4-1 4.5.6. Highest Precedence Operators 4-2 4.6. Type Conversions 4-2 4.7. Qualified Expressions 4-2 4.8. Allocators 4-2 4.9. Static Expressions and Static Subtypes 4-2 4.9.1. Statically Matching Constraints and Subtypes [new] 4-2 5. Ada 9X Statements 6-1 5.1. Simple and Compound Statements - Sequences of Statements 6-1 5.2. Assignment Statement 6-1 5.3. If Statements 6-1 5.4. Case Statements 6-1 5.5. Loop Statements 6-1 5.6. Block Statements 6-1 5.7. Exit Statements 6-1 5.8. Return Statements 6-1 5.9. Goto Statements 6-1 6. Ada 9X Subprograms 6-1 6.1. Subprogram Declarations 6-1 6.2. Formal Parameter Modes 6-1 6.3. Subprogram Bodies 6-1 6.3.1. Conformance Rules 6-1 6.3.2. Inline Expansion of Subprograms 6-1 6.4. Subprogram Calls 6-1 6.4.1. Parameter Associations 6-1 6.4.2. Default Parameters 7-1 6.5. Function Subprograms 7-1 6.6. Parameter and Result Type Profile - Overloading of Subprograms 7-1 6.7. Overloading of Operators 7-1 7. Ada 9X Packages 7-1 7.1. Package Structure 7-1 7.2. Package Specifications and Declarations 7-1 7.3. Package Bodies 7-1 7.4. Private Type and Deferred Constant Declarations 7-1 7.4.1. Private Types 7-1 7.4.2. Private Extension [new] 7-1 7.4.3. Operations of a Private Type [originally 7.4.2] 7-1 7.4.4. Deferred Constants [originally 7.4.3] 7-1 7.4.5. Limited Types [originally 7.4.4] 7-1 7.4.6. Controlled Types [new] 8-1 7.5. Example of a Table Management Package 8-1 7.6. Example of a Text Handling Package 8-1 8. Ada 9X Visibility Rules 8-1 8.1. Declarative Region 8-1 8.2. Scope of Declarations 8-1 8.3. Visibility 8-1 8.4. Use Clauses 8-1 8.5. Renaming Declarations 9-1 8.6. The Package STANDARD 9-1 8.7. The Context of Overload Resolution 9-1 9. Ada 9X Tasks and Synchronization 9-1 9.1. Task Specifications and Task Bodies 9-1 9.2. Task Types and Task Objects 9-1 9.3. Task Execution - Task Activation 9-1 9.4. Task Dependence - Termination of Tasks 9-1 9.5. Protected Specifications and Protected Bodies [new] 9-1 9.6. Protected Types and Protected Objects [new] 9-1 9.7. Protected Operations, Entry Calls, and Accept Statements 9-2 [originally 9.5] 9.7.1. Requeue Statements [new] 9-3 9.8. Delay Statements, Duration, and Time [originally 9.6] 9-3 9.9. Select Statements [originally 9.7] 9-3 9.9.1. Selective Wait [originally 9.7.1] 9-3 9.9.2. Conditional Entry Calls [originally 9.7.2] 9-3 9.9.3. Timed Entry Calls [originally 9.7.3] 9-3 9.9.4. Asynchronous Transfer of Control [new] 9-3 9.10. Priorities [originally 9.8] 9-3 9.11. Task and Entry Attributes [originally 9.9] 10-1 9.12. Abort of a Task; Abort of a Sequence of Statements [originally 10-1 9.10] 9.13. Shared variables [originally 9.11] 10-1 9.14. Example of Tasking and Synchronization [originally 9.12] 10-1 10. Ada 9X Program Structure and Compilation Issues 10-1 10.1. Compilation Units - Library Units 10-1 10.1.1. Context Clauses - With Clauses 10-1 10.1.2. Main Subprograms, Partitions, and Environment Tasks 11-1 [new] 10.1.3. Examples of Compilation Units [originally 10.1.2] 11-1 10.2. Subunits of Compilation Units 11-1 10.2.1. Examples of Subunits 11-1 10.3. Order of Compilation 11-1 10.4. The Program Library 11-1 10.5. Elaboration of Library Units 11-1 10.5.1. Library Unit Package Categorization [new] 11-1 10.6. Program Optimization 11-1 11. Ada 9X Exceptions 11-1 11.1. Exception Declarations 11-1 11.2. Exception Handlers 11-1 11.3. Raise Statements 12-1 11.4. Exception Handling 12-1 11.4.1. Exceptions Raised During the Execution of Statements 12-1 11.4.2. Exceptions Raised During the Elaboration of Declarations 12-1 11.5. Exceptions Raised During Task Communication 12-1 11.6. Exceptions and Optimization 12-1 11.7. Suppressing Checks 12-1 12. Ada 9X Generic Units 12-1 12.1. Generic Declarations 12-1 12.1.1. Generic Formal Objects 12-1 12.1.2. Generic Formal Types 12-1 12.1.3. Generic Formal Subprograms 12-1 12.1.4. Generic Formal Packages [new] 12-1 12.2. Generic Bodies 12-2 12.3. Generic Instantiation 12-2 12.3.1. Matching Rules for Formal Objects 12-2 12.3.2. Matching Rules for Formal Private Types 12-2 12.3.3. Matching Rules for Formal Scalar Types 12-2 12.3.4. Matching Rules for Formal Array Types 12-2 12.3.5. Matching Rules for Formal Access Types 12-2 12.3.6. Matching Rules for Formal Derived Types [new] 12-2 12.3.7. Matching Rules for Formal Subprograms [originally 13-1 12.3.6] 12.3.8. Matching Rules for Formal Packages [new] 13-1 12.4. Example of a Generic Package 13-1 13. Ada 9X Representation Clauses and Implementation-Dependent Features 13-1 13.1. Representation Clauses 13-1 13.2. Attribute Definition Clauses [originally Length Clauses] 13-1 13.3. Enumeration Representation Clauses 13-1 13.4. Record Representation Clauses 13-1 13.5. Address Clauses 13-1 13.5.1. Interrupts 13-1 13.6. Change of Representation 13-1 13.7. The Package SYSTEM 13-1 13.7.1. System-Dependent Named Numbers 14-1 13.7.2. Representation Attributes 14-1 13.7.3. Representation Attributes of Real Types 14-1 13.8. Machine Code Insertions 14-1 13.9. Interface to Other Languages 14-1 13.10. Unchecked Programming 14-1 13.10.1. Unchecked Storage Deallocation 14-1 13.10.2. Unchecked Type Conversions 14-1 13.10.3. Unchecked Access Value Creation 14-1 14. Ada 9X Input-Output 14-1 14.1. External Files and File Objects 14-1 14.2. Sequential and Direct Files 14-1 14.2.1. File Management 14-1 14.2.2. Sequential Input-Output 14-1 14.2.3. Specification of the Package Sequential_IO 14-1 14.2.4. Direct Input-Output 14-1 14.2.5. Specification of the Package Direct_IO 14-1 14.3. Text Input-Output 14-1 14.3.1. File Management 14-1 14.3.2. Default Input and Output Files 14-1 14.3.3. Specification of Line and Page Lengths 14-1 14.3.4. Operations on Columns, Lines, and Pages 14-2 14.3.5. Get and Put Procedures 14-2 14.3.6. Input-Output of Characters and Strings 14-2 14.3.7. Input-Output for Integer Types 14-2 14.3.8. Input-Output for Real Types 14-2 14.3.9. Input-Output for Enumeration Types 14-2 14.3.10. Specification of the Package Text_IO 14-2 14.4. Exceptions in Input-Output 14-2 14.5. Specification of the Package IO_Exceptions 14-2 14.6. Low Level Input-Output 14-2 14.7. Stream Input-Output [new] 14-2 14.7.1. T'READ and T'WRITE [new] 14-2 14.7.2. Predefined T'WRITE and T'READ [new] 14-2 14.7.3. Validation on T'READ [new] 14-2 14.7.4. T'WRITE and T'READ for Tagged Class-Wide Types [new] 14-2 14.7.5. The Package STREAM_SUPPORT [new] 14-2 14.7.6. Heterogeneous Input-Output [new] 14-3 14.8. Example of Input-Output 14-3 Index I-1 0. Reader's Guide to the Ada 9X Mapping Specification Snapshot This ``snapshot'' of the Mapping Specification is provided for reference purposes only. It represents an initial attempt to incorporate the decisions of the April '92 ISO WG9 and Distinguished Reviewer meetings. Change bars represent changes relative to version 4.0 of the Mapping Specification. In some cases, we have not completely fulfilled the recommendations of the WG9 and DR meetings. In these cases, we have included explanatory notes. We intend to use this document as the basis for the revision phase, but these cases and others will of course be again open for comment and refinement during this new phase. Only chapters 3 to 14 are included. 3. Ada 9X Declarations and Types 3.1. Declarations A declaration introduces a view of an entity (and usually, as in Ada 83, the entity itself). The same entity may have several different views. For example, a private type declaration and the corresponding full type declaration introduce different views of the same type. This term will be defined more precisely during the revision; we use it in this document to explain such things as conversions of actual parameters (see 4.6). Protected_declaration (see 9.5) is added to the list of basic declarations. 3.2. Objects and Named Numbers 3.2.1. Object Declarations [Note: We were asked to further investigate the issue of parameterized | parallel task activation. Here is a possible alternative approach: | | To support parameterized parallel task activation, it would be useful to | allow an object declaration of an anonymous limited array type to allow an | iterator notation, as follows: | | object_declaration ::= | ... -- As in Ada 83 | | identifier_list : array(for identifier in discrete_range | {, for identifier in discrete_range}) | of limited_type_mark discriminant_constraint; | | Such a declaration would initialize an array of limited components, with the | discriminant constraint expressions parameterized by the identifiers | appearing in the iterators. This provides more direct support for parallel | parameterization than the iterator-in-aggregate mechanism, since parallel | activation is already the rule for an array of tasks. By restricting it to | limited types, we avoid problems associated with assigning or comparing | ragged arrays, while allowing it to be used for arrays of protected objects | acting as device drivers, etc.] | 3.2.2. Number Declarations 3.3. Types and Subtypes As in Ada 83, a type has an associated set of values, and an associated set of operations. A class is a set of types with similar values and | operations, which is closed over derivation. As in Ada 83, types are | grouped into language-defined classes, such as integer, real, task, etc. In | addition, in Ada 9X, types are grouped into derivation classes, each formed | by the root type for the class and its derivatives (direct and indirect). | A specific type is a type declared by a type declaration, task type declaration, or protected type declaration. In addition to specific types, | there are class-wide types (used in conjunction with task types and tagged | types, -- see 3.4.1) and universal types (used in conjunction with numeric | types -- see 3.5.4 and 3.5.6). | A type is either an elementary type or a composite type. Elementary types are the scalar types and access types. Composite types are the array, record, private, task, and protected types. (Protected types are described in chapter 9.) [Notes on terminology: The term ``specific type'' corresponds to the normal | types in Ada 83. It is introduced to differentiate them from the (new) | ``class-wide'' types and the (preexisting) ``universal'' types. | In Ada 83, composite types include only record and array types. Here we generalize it to include all types other than scalar and access. The term ``elementary type'' is new with Ada 9X, to simplify descriptions that in Ada 83 use the phrase ``scalar and access types.''] 3.3.1. Type Declarations A type declaration introduces a type and a first-named subtype. The name | given in the type declaration is the name of the subtype. [Note: This is | true in many cases for Ada 83; for simplicity, we make it true in all cases | for Ada 9X.] | | As in Ada 83, a subtype determines a type and a possibly null constraint. | An unconstrained subtype is one with a null constraint. Given a subtype S | for an elementary type, S'BASE denotes the unconstrained subtype of the same | elementary type. | | In later descriptions, when we refer to properties of a ``type T,'' we are | describing properties that apply to the type in general, rather than to any | particular subtype of the type. | | [Note: Types are never directly named; all type marks denote subtypes. | Therefore, when we use the term anonymous type we really mean a type that | has no nameable subtypes. Anonymous types are declared implicitly as part | of certain other declarations, such as single task declarations, single | protected declarations, and array and access definitions.] | 3.3.2. Subtype Declarations Floating point and fixed point accuracy constraints are removed from the syntax. A decimal digits constraint may be applied to a decimal fixed point | type (see 3.5.9). | constraint ::= range_constraint | index_constraint | discriminant_constraint | decimal_digits_constraint | It is illegal to apply a constraint to a tagged class-wide type (see 3.4.1) or to a generic formal type with (<>) for its discriminant part (see | 12.1.2), as they have an unknown set of discriminants. 3.3.3. Classification of Operations The primitive operations of a specific type are the implicitly declared operations of the type, and, for a type declared within a package | specification, any subprogram with a formal parameter of the type, result of | the type, or access parameter (see 3.9) designating the type, explicitly declared immediately within the same package specification as that of the | type declaration. For a protected or task type, the primitive operations also include the protected operations (see 9.7). The implementation of an implicitly declared primitive operation may be | overridden by providing a new declaration for the primitive operation, | immediately within the same package specification or declarative part as | that of the type declaration. | We define operand matching rules that determine what operands may be passed to what operations. To simplify description, we say that one type covers another if they are the same type, or if the first type is the universal or class-wide type for a class that contains the second type. The expected | type for an operand determines the types that are allowed for actual | operands, as follows: | | - If the expected type and the actual type are both specific types, | then they must be the same type; | | - If the expected type or the actual type is a universal type then | one of the types must cover the other; | | - If the expected type is a class-wide type, then it must cover the | actual type; | | - If the expected type is a specific type, and the actual type is a | class-wide type, then the operand must be a controlling operand | (see 3.4.2) and the class-wide type must be for the class rooted | at the expected type. | | If the formal is an access parameter (see 3.9), then the actual operand is | the object designated by the value of the actual parameter, and the expected | type of that operand is the designated type of the access parameter. | Class-wide and universal types do not have their own primitive operations, | nor any implicitly declared operations other than attributes. Because of | the operand matching rules, the primitive operations of the root type for a | class may be used for operands of the corresponding class-wide or universal | type. | A subprogram with a formal parameter or result of a class-wide type may be explicitly declared. Such subprograms are referred to as class-wide operations. For an elementary subtype S, the attribute S'BASE is allowed to appear | wherever a type mark may appear, rather than strictly as a prefix for other | attributes. | 3.4. Derived Types The syntax for a derived type definition is amended to include an optional type extension part (see 3.4.1): derived_type_definition ::= new subtype_indication [type_extension_part] A type extension part is allowed only for tagged types (see 3.4.1). The description of the characteristics of a derived type is revised as follows: - The value set of a derived type is a (possibly modified) copy of the parent's value set. The copy is modified in these cases: * If the derived type declaration includes a discriminant part (see 3.6.1), then the parent subtype must be constrained, and the discriminants of the derived type are those given in the new discriminant part. Otherwise, as in Ada 83, the derived type has the same discriminants as the parent type, if any. [Note: The constraint on the parent may depend on the new discriminants -- see 3.6.1.] * If the derived type declaration includes a record extension | part (see 3.4.1), then the parent subtype must be constrained, and the values consist of the discriminants (if any), followed by the non-discriminant components of the parent type, followed by the components of the record | extension part. - The derived type inherits the primitive operations of the parent type that are declared prior to the derivation, obtaining the | specification of these operations by systematic replacement of the parent type with the derived type, where it appears as the type of a formal parameter or result (as in Ada 83 -- see RM 3.4(13)), or as the designated type of an access parameter (see 3.9). - If an explicitly declared primitive operation of a derived type is a homograph of an inherited operation, then the explicitly declared operation overrides the inherited one. - As in Ada 83, when STANDARD.BOOLEAN is the parent type, the result type is not replaced when inheriting the predefined relational operators and membership tests; the result type remains STANDARD.BOOLEAN for these operations of the derived type (RM 3.4(21)). For a composite type, the parent part consists of all components inherited from the parent type, and the extension part consists of any other components. The parent type in a derived type definition must not be a class-wide type, nor an unconstrained generic formal type with an unspecified set of discriminants (see 12.1.2). 3.4.1. Tagged Types and Type Extensions [new] A tagged type is a record or private type that provides a type tag that represents, at run time, the identity of the type. Tagged types support type extension (see below). A record or private type is tagged if its declaration includes the reserved word tagged, or if it is derived from a tagged type. The derived type definition for a type derived from a tagged type must | include a type extension part: type_extension_part ::= with record_type_definition | with private | | with null | A tagged type must be extended with either a record extension part (with | record_type_definition -- see 3.8.2), private extension part (with private | -- see 7.4.2), or null extension part (with null). A derived type defined | in one of these ways is called a type extension of its parent type. [Note: | By requiring with null we ensure that all tagged types include either the | reserved word tagged or with in their declaration. Furthermore, it | emphasizes that normal type conversion cannot be used to construct a value | of the derived type given a value of the parent type, but instead an | extension aggregate using with null must be used (see 4.3.1). This should | enhance readability (at some expense of writability, though we expect null | extensions to be less common than record extensions.] | Example of declaration and extension of a tagged type: type VEHICLE is tagged record WEIGHT : KILOGRAMS; end record; type CAR is new VEHICLE with record NUMBER_OF_DOORS : POSITIVE range 1..5; NUMBER_OF_WINDOWS : POSITIVE range 4..8; NUMBER_OF_WHEELS : POSITIVE range 3..4; end record; When a tagged type T is declared, an associated class-wide type, denoted by | T'CLASS, is implicitly declared. The value set for T'CLASS is the union of | the value sets of the specific types in the derivation class rooted at | T. The union is a discriminated union, with the type tag as the (implicit) | discriminant. | | Given a tagged subtype S for the type T, S'CLASS denotes a subtype of | T'CLASS. A value of type T'CLASS belongs to S'CLASS if it satisfies the | constraints applicable to S. | If a tagged type's parent is not limited, then any extension part must not contain any limited components. The scope level (see 8.2) of a derived tagged type declaration must be the same as that of its parent. [Note: Thus, all types included in a tagged class are at the same scope level.] A primitive operation of a derived tagged type that overrides an inherited operation must be subtype conformant (see 6.3.1) with the inherited operation. For a tagged type, the declaration of a primitive operation must not occur | after a forcing occurrence (see RM 13.1(6)) of the type. [Note: This | restriction minimizes confusion by ensuring that the implementation reached | via a dispatching call corresponds to the operation declared immediately | within the declarative region where the type is declared. This also implies | that all overridings for a tagged type must be declared prior to subprogram | bodies, even for tagged types declared in a package body.] | The declaration of a tagged derived type with a record or null extension | part is considered a forcing occurrence for the parent type. [Note: This | combined with the previous rule ensures that all derivatives of a tagged | type inherit all of its primitive operations, so that dispatching will work | properly.] | Each tagged specific type T has a tag value, which represents the identity of the type at run time. A tag value uniquely identifies a particular | tagged type declaration. Repeated elaborations of the same declaration need | not produce distinct tag values, nor do repeated instantiations of the same | generic body. However, distinct instantiations of the same generic | specification containing a declaration for a tagged type must produce | distinct tag values. | Each value of a tagged class-wide type has a tag, which reflects the specific type from which the value originated, possibly through one or more (view) conversions (see 4.6). Each object of a tagged class-wide type must be explicitly initialized, and is constrained thereafter to hold only values with tag and any discriminants matching those of its initial value. 3.4.2. Operations of Tagged Types [new] By definition, a primitive operation (see 3.3.3) of a type T has a formal parameter of type T, return type T, or an access parameter (see 3.9) designating T. The actual parameter passed to a formal parameter of type T is called a controlling operand of the primitive operation. The object designated by the actual parameter passed to an access parameter designating T is also a controlling operand. If the return type is T, the result of the operation is called a controlling result of the primitive operation. For a tagged type, the primitive operations are called dispatching operations, because when applied to a controlling operand that is class-wide, they automatically dispatch to the appropriate implementation of the operation. A call to a dispatching operation of a tagged type T works as follows: - If there are no class-wide controlling operands anywhere in the context that determine the tag (as defined by the next bullet), then the controlling tag value is by definition that for T. (this is a normal ``static'' binding case). - Otherwise, each controlling operand determines a tag: * If the operand is class-wide, the tag is that of the operand's value; * If the operand is a controlling result of a dispatching operation, the tag is the same as the controlling tag value of that operation; * Otherwise, the tag is that of the specific type of the operand (which, according to the matching rules, must identify T, i.e. this is a ``static'' binding case). If all controlling operands determine the same tag value, then this is the controlling tag value for the operation. Otherwise, CONSTRAINT_ERROR is raised, or, in the case of an equality operator ("=" or "/=") whose result is of type BOOLEAN, inequality is indicated. - The controlling tag value determines the particular implementation of the operation to be invoked. The implementation selected is the one for the corresponding primitive operation of the specific type identified by the tag. If a dispatching operation has a controlling result, but has no operand that determines a tag, then its controlling tag is chosen to match that required by its context, in order to avoid CONSTRAINT_ERROR. If a single operation is a primitive for more than one tagged type, then in | a given call, only one of the types may have actual controlling operands | that are class-wide. [Note: We shifted this check to the call rather than | the declaration, to handle situations where an operation is declared on two | private types that both turn out to be tagged in their full type | declarations.] | | [Note: We are also considering disallowing calls where some of the | controlling operands of a given type are class-wide, while others have | statically-determined tags. Such calls seem to be a possible source of | confusion.] | If a tagged type has any primitive operations that are declared as abstract | (see 6.1), then it is called an abstract type, and it is illegal to create an object of that type, and a value of the type must only be produced via a conversion (see 4.6). [Note: This disallows, for example, object declarations, allocators, aggregates, using the type as a generic actual, | and non-abstract functions returning the type.] | When calling an abstract primitive operation of a tagged type T, the controlling tag value must not be that of type T. [Note: This check can be performed at compile-time, because there are no values of the class-wide type T'CLASS with tags identifying type T.] When deriving from an abstract type, all primitive operations that are | abstract for the parent type must be overridden for the derived type, | possibly with another abstract subprogram declaration (see 6.1). As in Ada | 83, an inherited operation with a result of the derived type is defined in | terms of a conversion of the result returned by the parent type's operation. | If the parent type is tagged, conversion to the derived type is not defined | (see 4.6), so the inherited operation must be overridden, just as though it | had been an abstract operation of the parent type. | Note: | | All primitive operations of a tagged type are dispatching, whether | inherited, defined by an instantiation, a renaming declaration, or a normal | subprogram declaration. On the other hand, non-primitive operations are | never dispatching, even when they are defined by renaming a dispatching | operation. | 3.5. Scalar Types 3.5.1. Enumeration Types 3.5.2. Character Types The predefined type CHARACTER will be changed to have 256 positions, the first 128 of which will correspond to ASCII. A new predefined type WIDE_CHARACTER will be provided, to support character sets with more than 256 positions, in accordance with the recommendations of the CRG (see chapter 2). All character literals are directly visible throughout their scope. The | type of a character literal must be determinable solely from context, but | using the fact that the literal is a value of some character type. The | character literal must be one of the character literals of the type | (although this is not used to determine the type of the literal). [Note: | This is to be consistent with other ``unrenamable'' literals: string | literals; null; and the numeric literals (see RM 4.2(4)). Since there will | be two character types in scope at all times (CHARACTER and WIDE_CHARACTER), | it is simpler to always use context to resolve the type of a character | literal than to try to use the particular character itself to determine the | type.] | 3.5.3. Boolean Types 3.5.4. Integer Types By definition, all integer types are derived (directly or indirectly) from | root_integer. In addition, a universal type, universal_integer, is defined | for the integer class. Integer literals and integer named numbers are | defined to yield a value of this universal type. The operand matching rules | (see 3.3.3) allow a universal integer to be used as an actual operand if the | expected type is some specific integer type. | | The VAL attribute is defined to have an operand of the universal type | universal_integer, which allows an actual operand of any integer type. | | Values of universal_integer may be combined using the predefined operators | of any specific integer type. However, in the case of ambiguity, there is a | preference for the operators of the root_integer type (see 8.7). [Note: The | operators of root_integer correspond to the predefined operators of | universal_integer in Ada 83. The result of such an operator is never | universal. This eliminates the need for the special case rules governing | ``convertible universal operands'' given in RM 4.6(15).] | The value set for all integer types is the (infinite) set of mathematical integers. For static calculations with the operators of root_integer, an | implementation must support all such values (see 4.9). For run-time | calculations, an implementation may restrict integer values to a finite | range. The FIRST and LAST attributes of an unconstrained integer subtype | specify the minimum range supported by the implementation for run-time | operations on values of the corresponding integer type. At run-time, a | predefined operation taking or yielding an integer value outside of this minimum range either produces the correct mathematical result, or raises CONSTRAINT_ERROR. As in Ada 83, the FIRST and LAST attributes of a constrained integer subtype represent constraints on the value of any object of the subtype. The run-time range of the root_integer type is at least SYSTEM.MIN_INT .. | SYSTEM.MAX_INT (see RM 13.7.1). | STANDARD.INTEGER'LAST is at least 2**15-1. If an implementation provides STANDARD.LONG_INTEGER, then the value of its LAST attribute is at least 2**31-1. As in Ada 83, an integer type definition selects a parent type from one of | those defined in package STANDARD. These types are called the standard | integer types. An implementation may also provide additional non-standard | integer types declared outside package STANDARD. Such types may have a | run-time range outside of SYSTEM.MIN_INT .. SYSTEM.MAX_INT, and need not be | symmetrical around zero. An implementation may restrict the use of such | types; in particular, they need not be allowed as array or loop indices. | [Notes: Non-standard integer types may not be used as generic actual types | for a formal integer type or formal discrete type -- only for formal private | and formal derived types. The System Programming Annex defines requirements | for unsigned types to be provided in package SYSTEM.UNSIGNED_SUPPORT. Such | types are considered non-standard integer types.] | 3.5.5. Operations of Discrete Types 3.5.6. Real Types The syntax is amended to remove accuracy constraints, as explained in section 3.3.2. real_type_definition ::= floating_point_definition | fixed_point_definition By definition, all real types are derived from root_real. In addition, a | universal type universal_real is defined for the real class of types. Real | literals and real named numbers are of type universal_real, as are the | results of certain attributes. | | Values of type universal_real may be combined using the predefined operators | of any specific real type. However, in the case of ambiguity, there is a | preference for the operators of root_real (see 8.7). | The value set for all real types is the infinite set of rational numbers. | For static calculations with the operators of root_real, an implementation | must support all such values. For run-time calculations, an implementation | may use approximations and may restrict the range. The attributes of a real type define the maximum relative (floating-point) or absolute (fixed-point) error and minimum range supported by the implementation for representing and operating on run-time values. If the MACHINE_OVERFLOWS attribute is true, then at run-time, a predefined operation taking or yielding a real value outside of this minimum range either produces the correct result (as defined by the accuracy model -- see NM:ALL), or raises CONSTRAINT_ERROR. As in Ada 83, the FIRST and LAST attributes of a constrained real subtype represent constraints on the value of an object of the subtype. At run-time, the root_real type is a floating point type, and its DIGITS | attribute is at least SYSTEM.MAX_DIGITS (see RM 13.7.1). The LARGE | attribute for root_real is at least as great as any other floating point | type declared in STANDARD with DIGITS equal to SYSTEM.MAX_DIGITS. | STANDARD.FLOAT'DIGITS is at least 6. If an implementation provides STANDARD.LONG_FLOAT, then the value of its DIGITS attribute is at least 11. In accordance with AI-00174, the values of the FIRST and LAST attributes of a real type depend on the representation chosen for the type. Therefore, a range constraint on a real type is a forcing occurrence (RM 13.1(6)) for the type. [Note: This eliminates certain anomalies relating to the fact that determining whether a range constraint is compatible with the real type requires selecting the representation for the type.] As in Ada 83, a floating point or fixed point type definition selects a | parent type from one of those defined in package STANDARD. These types are | called the standard real types. An implementation may also provide | additional non-standard real types declared outside package STANDARD. Such | types may have a DIGITS attribute greater than SYSTEM.MAX_DIGITS, or a | mantissa greater than SYSTEM.MAX_MANTISSA. An implementation may restrict | the use of such types; in particular, they need not have a full set of | attributes. [Notes: Non-standard real types may not be used as generic | actual types for a formal floating point type or formal fixed point type.] | 3.5.7. Floating Point Types The syntax is amended to remove accuracy constraints, as explained in section 3.3.2. floating_point_definition ::= digits static_simple_expression [real_range_specification] real_range_specification ::= range static_simple_expression .. static_simple_expression 3.5.8. Operations of Floating Point Types 3.5.9. Fixed Point Types The syntax is amended to remove accuracy constraints, as explained in section 3.3.2. fixed_point_definition ::= delta static_simple_expression real_range_specification | decimal_fixed_point_definition decimal_fixed_point_definition ::= | delta static_simple_expression | digits static_simple_expression [real_range_specification] | | decimal_digits_constraint ::= | digits static_simple_expression [range_constraint] | A fixed point type declared with both a delta and a digits is a decimal | fixed point type. The specified delta must be a power of 10, and the small | is defined to equal the delta. | | The DIGITS attribute of a decimal fixed point subtype is determined by the | decimal digits constraint that applies to it. The FIRST and LAST attributes | of a decimal fixed point subtype are determined by the range constraint, if | any, that applies to it. In the absence of a range constraint, the FIRST | and LAST attributes are determined by the applicable digits constraint, such | that LAST = delta*(10.0**digits-1.0) and FIRST = -LAST. | Notes: For implementations that conform to the Information Systems Annex, smalls | that are a power of 10 must be supported, as well as at least 18 digits for | a decimal fixed point definition. See IS:ALL. | 3.5.10. Operations of Fixed Point Types 3.6. Composite Types [new] Composite types may have components, including special components called discriminants. The rules regarding declarations of a variable of a composite type are relaxed to conform to the rules regarding constant declarations, namely that if the subtype indication is for an unconstrained subtype with undefaulted discriminants or unconstrained array bounds, then there must be an initialization expression, and the constraints of the variable are defined by the initial value. 3.6.1. Discriminants [originally RM 3.7.1] Discriminants represent a general method for parameterizing types. The syntax for discriminant specifications is modified to allow an access discriminant, with a type specified by an access definition (see 3.9): discriminant_specification ::= identifier_list : type_mark [:= expression] | identifier_list : access_definition [:= expression] | A discriminant part may only be specified in a type declaration for a | composite type that is not an array type. The type of an access | discriminant is an anonymous general access type (see 3.9). The type of | other discriminants must be discrete. | Only a limited type may have an access discriminant. | If a discriminant part is specified in a derived type declaration, then the parent subtype must be constrained. Analogous to the Ada 83 rule for component constraints (RM 3.7.1(6)), when a discriminant is used in a constraint on the underlying type, it must appear alone (not as part of a larger expression). In addition, if discrete, its | subtype must be statically compatible with the underlying discriminant | subtype (see 4.9.1). [Note: This restriction minimizes the checking | required on type conversion. See 4.6.] | For a tagged type, the discriminants specified in a derived type declaration need not be used to constrain the parent subtype. Within the definition of a type with a discriminant part, the name of a discriminant may be used in an expression. However, as in Ada 83, a discriminant may not be used in a component's range constraint, and when used in other constraints, it must be used alone, not as part of a larger expression. Within a task or protected body, a discriminant acts as a formal in parameter to the unit. 3.6.2. Discriminant Constraints [originally RM 3.7.2] 3.7. Array Types [originally RM 3.6] 3.7.1. Index Constraints and Discrete Ranges [originally RM 3.6.1] The rules for determining the type of a discrete range are revised so that if the type for both bounds is either root_integer or universal_integer, | then the type for the range is STANDARD.INTEGER. [Note: This resolves the Ada 83 problem where ``for I in -1 .. 100'' is ambiguous.] 3.7.2. Operations of Array Types [originally RM 3.6.2] 3.7.3. String Types [originally RM 3.6.3] An additional predefined string type WIDE_STRING will be provided, defined as an array of WIDE_CHARACTERs indexed by POSITIVE, in accordance with the recommendations of the CRG (see chapter 2). 3.8. Record Types [originally RM 3.7] A type definition for a record type may include the reserved words tagged and limited: type_definition ::= . . . as in Ada 83 | [tagged] [limited] record_type_definition If the reserved word tagged appears, the record type is a tagged type, and may be extended in a type derivation (see 3.4.1). If the reserved word limited appears, the record type is limited throughout its scope (that is, equality and assignment are not predefined -- see 7.4.5). [Note: The concept of an explicitly limited record type has been retained | pending further review. Because finalization, limited type extension, and | access discriminants are all dependent on the use of limited types | independent of privateness, we prefer to retain the ability to specify | limitedness without specifying privateness.] | [Note: The subsections on Discriminants have been moved to 3.6.1 and 3.6.2.] 3.8.1. Variant Parts [originally RM 3.7.3] [Note: As in Ada 83, a discriminant controlling a variant part must be discrete.] 3.8.2. Record Extension [new] A tagged record or tagged private type may be extended with a record extension part (see 3.4.1). Within the extension part, the value of an access discriminant (see 3.6.1) of a component may be specified by an ACCESS attribute whose prefix is the simple name of the derived type being declared. When used in this way, the attribute designates the enclosing object being initialized. [Note: This allows a form of ``multiple inheritance,'' by embedding a component with an access discriminant that designates the enclosing object.] [Note: The Ada 83 rules for naming of record components (RM 3.7(3)) imply that overriding the components of a visible record type in the extension part is illegal. However, in a record extension of a private type, a component in the extension part may have the same name as a component of the private parent part; as in Ada 83, the parent part remains private throughout the scope of the type extension.] 3.8.3. Operations of Record Types [originally RM 3.7.4] 3.9. Access Types [originally 3.8] The syntax for access type definitions is changed to support general access types (including access-to-constants) and access-to-subprograms. access_type_definition ::= access [general_access_modifier] subtype_indication | access [protected] procedure [formal_part] | access [protected] function [formal_part] return type_mark general_access_modifier ::= all | constant An access value is either null, or designates some entity. Access-to-object values designate objects. Access-to-subprogram values designate subprograms. There is a storage pool associated with each access-to-object type. An allocator for an access-to-object type allocates in that type's pool. An access type with a general access modifier is a general access type. Values of a general access type may be produced by allocators, by conversion from other access types (see 4.6), and by use of the ACCESS attribute (see 3.9.2). If the modifier is the reserved word constant, then the designated object may only be read through a value of such a type. If the modifier is the reserved word all, then the designated object may be both read and updated through a value of such a type. Other access-to-object types are pool-specific access types, which correspond to the access types of Ada 83. Values of such types may only be produced by allocators (and, as in Ada 83, by conversion from an access type derived from some common ancestor). An access definition may be used to specify a formal in parameter (see 6.1) | or a discriminant (see 3.6.1): | | access_definition ::= access type_mark | | Such a parameter or discriminant is of an anonymous access type. An | anonymous access type is a general access-to-variable type, implicitly | declared at the point of the access definition. Its designated subtype is | that denoted by the type mark. An anonymous access type has no primitive | operators of its own. [Note: An access discriminant or parameter may be | converted (see 4.6), used as a prefix of a name (see RM 4.1(8)), used to | initialize another access discriminant, or passed as an actual parameter | where the formal is an access parameter (see 3.3.3).] [Notes: The language rules (see 3.9.2 and 4.6) ensure that (unless the unchecked programming features of Chapter 13 are used) a pool-specific access value will always designate an object allocated from its own pool. By contrast, a general access value can designate an object allocated from any pool, or created by an aliased object declaration, so long as the object is of an appropriate subtype and scope level. Which pool is associated with an access type is implementation defined, if not user specified. Sections 13.2 and SP:ALL define methods for specifying the storage pool of an access type, and for specifying various aspects of the pools themselves. Several access types may share the same pool. Access parameters support tag-based dispatching on access values (see 3.4.2). They also provide a way to pass a reference to an aliased local variable to a subprogram. All objects of an anonymous access type are constants. The object designated by an access discriminant or parameter is a variable. A value of an anonymous access type is never null. A run-time check is made when the value of an access parameter or discriminant is specified to ensure that it is not null (see 4.6). A run-time scope check is performed when an access parameter is converted to another general access type, to ensure that it is not designating an object at a deeper scope-level than that of the resulting access type (see 4.6). Pools and the terms ``general''/``pool-specific'' are not defined for access-to-subprogram types. There is no requirement that the ACCESS attribute of a particular subprogram always yield the same value. The value of the attribute may designate, for example, a locally generated interface routine needed to support an indirect call. End of Notes.] 3.9.1. Incomplete Type Declarations [originally 3.8.1] 3.9.2. Operations of Access Types [originally 3.8.2] General access types may only designate aliased objects. The object created by an allocator is an aliased object. All objects of a limited tagged type, | or non-private limited type, are inherently aliased. [Note: We would have | made all limited types inherently aliased, except that a limited private | type may be completed with an elementary type, which can't be passed by | reference. Inherent aliasing is important for parameter passing and | function return of task types, protected types, controlled types, types with | access discriminants, and types composed of such types (see 7.4.5). This | issue will receive further study during the revision phase.] An object or | component with the reserved word aliased in its object or component subtype definition is aliased. The following new syntax is provided for this purpose: object_declaration ::= identifier_list : [constant] object_subtype_definition [:= expression]; object_subtype_definition ::= [aliased] subtype_indication | [aliased] array_type_definition component_subtype_definition ::= [aliased] subtype_indication unconstrained_array_definition ::= ... of component_subtype_definition constrained_array_definition ::= ... of component_subtype_definition An aliased object with discriminants is constrained by the initial value of its discriminants, whether created by an allocator or by a declaration. [Note: For allocators, this corresponds to the rule in Ada 83. The rule is necessary to support access subtypes safely.] For a type T, an allocator new T is overloaded on all access types designating types that cover T. If T is a tagged class-wide type, then the | allocator must specify an initial value. For an aliased object X of type T, X'ACCESS is overloaded on all general access types designating types that cover T. | For X'ACCESS, the constraints of X must statically match (see 4.9.1) the constraints on the designated subtype of the result type, unless it is an unconstrained subtype with discriminants. In Addition, the same | representation clauses and pragmas must apply to X that apply to the | designated subtype. Finally, X must not be a subcomponent that depends on | discriminants of a variable, if the discriminants have defaults, and the | variable might be unconstrained (see RM 8.5(5)). If X is constant, then the | type of X'ACCESS must be an access-to-constant type. The scope level of X must not be deeper than that of the resulting access type. The attribute S'ACCESS, when applied to a prefix S that denotes a subprogram, creates an access value that designates the subprogram. For an overloaded subprogram name S, S'ACCESS is overloaded on all access types designating subprograms. The context must uniquely determine such a type. The access type determined may then be used to identify the particular subprogram denoted by S. [Note: This use of context to resolve the overloading of an attribute prefix is new to Ada 9X. It is not permitted in Ada 83 -- see RM 4.1.4(3).] For S'ACCESS, the scope level of S (see 8.2) must not be deeper than that of the resulting access type. S must be subtype conformant (see 6.3.1) with the subprogram formal part and return subtype specified in the access type definition. S must be a protected subprogram, if and only if the definition of the resulting access type includes the reserved word protected. S must | not be an abstract subprogram (see 6.1). | The reserved word all is used for dereferencing all access types. The ``.all'' may be omitted when used as a prefix, or (for access-to-subprogram) followed by an actual parameter part. Any selected component with a value of an access-to-constant type as prefix is constant. [Note: Other access values might provide views of the same object; those views might be variable.] When an access-to-subprogram value is dereferenced, the resulting subprogram | is never a dispatching subprogram. | 3.10. Declarative Parts [originally 3.9] The ordering requirement between basic declarative items and later declarative items is eliminated. The occurrence of a body forces (see RM 13.1(6)) the determination of the representation of all types declared prior to the body. The syntax for declarative parts is modified as follows: declarative_part ::= {declarative_item} declarative_item ::= basic_declaration | representation_clause | use_clause | body body ::= proper_body | body_stub proper_body ::= subprogram_body | package_body | task_body | protected_body 4. Ada 9X Names and Expressions 4.1. Names 4.1.1. Indexed Components 4.1.2. Slices 4.1.3. Selected Components 4.1.4. Attributes 4.2. Literals 4.3. Aggregates 4.3.1. Record Aggregates A record aggregate for a type must not be used in a place where any extension part of the type is private (see 3.4.1). A special form of record aggregate, an extension aggregate, may be used to | specify a value for a tagged derived type in terms of a value of its parent | type, as follows: | | record_aggregate ::= | aggregate -- as before | | extension_aggregate | | extension_aggregate ::= | (expression with record_aggregate) | | (expression with null) | | [Note: This feature replaces the concept of constructor conversions that | appeared in earlier mapping specifications.] | | The derived type must be a record extension or null extension of the parent | type. The expression must be of the parent type. The nested record | aggregate, if present, must specify a value for each discriminant and each | component of the record extension part of the derived type. If with null is | specified, the derived type must be a null extension of the parent type with | all discriminants inherited from the parent type. | | For the evaluation of an extension aggregate, the expression of the parent | type and the expressions for the components in the nested record aggregate | are evaluated in an order based on the rules for normal record aggregates | (see RM 4.3.1 and AI-00189). [Note: This generally means in any order, | except for nested array aggregates or string literals whose bounds are | determined by a discriminant.] A check is made that the values specified by | the aggregate for the parent part and each component of the extension part | belong to the corresponding parent or component subtype, CONSTRAINT_ERROR is | raised if this check fails. | 4.3.2. Array Aggregates Paragraph 6 of RM 4.3.2, which deals with aggregates having both an others choice and other named associations, is removed. The presence of other named associations has no effect on the legality of the use of an others choice in an array aggregate. [Note: This is possible by stipulating that no implicit array subtype conversion (see 4.6) takes place on an array aggregate with an others choice.] 4.4. Expressions The restriction on the use of out parameters is eliminated. [Note: Prior to being assigned, out parameters are essentially like variables declared without an explicit initialization.] 4.5. Operators and Expression Evaluation 4.5.1. Logical Operators and Short-circuit Control Forms 4.5.2. Relational Operators and Membership Tests For a membership test of the form ``X in S'' where S is a subtype of type T, the type of X must cover or be covered by T. The result is TRUE if and only if X satisfies the constraints associated with subtype S, if any, and, if X is of a tagged class-wide type, the tag of X identifies a (specific) type covered by T. [Note: If X is of a tagged class-wide type, and T is a specific type, then X in T asks whether X'TAG = T'TAG, whereas X in T'CLASS asks whether X'TAG is the tag for T or any of its derivatives.] 4.5.3. Binary Adding Operators 4.5.4. Unary Adding Operators 4.5.5. Multiplying Operators Corresponding to the Ada 83 operators on universal_real, universal_integer, and universal_fixed, in Ada 9X, the following additional operators appear in package STANDARD for the root numeric types: function "*"(LEFT : root_real; RIGHT : root_integer) return root_real; function "*"(LEFT : root_integer; RIGHT : root_real) return root_real; function "/"(LEFT : root_real; RIGHT : root_integer) return root_real; The root_integer and root_real types also have the full set of operators defined in Ada 83 for integer and real types, respectively. Note that, the above operators on root_integer and root_real are not predefined for other numeric types. As in Ada 83, any two fixed point types may be multiplied or divided. In | addition, for Ada 9X, we allow either of the operands to be of type | universal_real. function "*"(LEFT, RIGHT : any_fixed_or_universal_real) return precise_fixed; function "/"(LEFT, RIGHT : any_fixed_or_universal_real) | return precise_fixed; | Like the Ada 83 type universal_fixed, the type precise_fixed is a real type with no operators, and must be converted before further use. [Note: In response to the April '92 DR meeting, we are investigating | allowing multiply and divide for fixed-point types to be used without | explicit conversion of the result, where the type of the result can be | determined unambiguously from context. This would treat these fixed-fixed | operations roughly the same way that null or string literals are treated, | requiring the result type of the multiply or divide to be determined from | context knowing only that it must be a fixed-point type. The simplest | formulation is as follows: | | function "*"(LEFT, RIGHT : universal_fixed) | return universal_fixed; | function "/"(LEFT, RIGHT : universal_fixed) | return universal_fixed; | | Universal fixed would cover all fixed point types (see 3.3.3 for definition | of "cover"), but there would be no predefined operators other than "*" and | "/" that would operate on it directly. In this way, it would be like a | literal without any preference rule, requiring a specific fixed-point type | to be provided by context to use the result.] | 4.5.6. Highest Precedence Operators In accordance with AI-00868, exponentiation by an integer is equivalent to repeated multiplication, but with arbitrary association of operands (that is, not necessarily left to right), followed by a final reciprocal for the case of a real operand with a negative exponent. [Note: Arbitrary association allows exponentiation by an integer to be performed using repeated squaring, rather than strictly as a sequence of single multiplications.] [Note: Section 4.5.7, Accuracy of Operations with Real Operands, is moved to Annex NM:ALL] 4.6. Type Conversions This section defines rules that govern whether it is legal to convert from one type to another. In addition, it specifies checks that are performed at run time as part of a type conversion. A type is convertible to a second type if and only if it is legal to convert from the first type to the second, according to the rules in this section. In what follows, the ancestor of a specific type T or class-wide type T'CLASS is defined to be the type T itself, or any type from which T is derived, directly or indirectly. A conversion denotes a view of its operand. The resulting view is of the | target subtype. For parameter passing purposes, a conversion of a variable | is a variable, a conversion of a constant is a constant, and a conversion of | a value is a value. The tag of a class-wide object or value is preserved | through a series of conversions. | Similar to Ada 83, a conversion between types is generally permitted if their root types share a common ancestor. However, there are additional restrictions for tagged types, and additional allowances for general access | types. The basic rules for conversions between tagged types are as follows: - The target type must cover an ancestor of the operand type, or the | operand type must cover the target type; | | - If only the latter case is true, then at run-time, a check is made | that the target type covers an ancestor of the specific type | identified by the tag of the operand. CONSTRAINT_ERROR is raised | if this check fails. In addition to conversions between access types with a common ancestor (which are allowed in Ada 83), Ada 9X allows conversions to access-to-subprogram types and general access types: - For conversion to an access-to-subprogram type, the operand's designated subprogram specification must be subtype conformant with that of the target type. - It is illegal to convert from an access-to-constant type to an access-to-variable type. - For conversion to a general access type, the operand and target | designated types must be convertible. If there is a run time tag | check associated with converting from the operand designated type | to the target designated type, this check is performed if the | operand is not null. CONSTRAINT_ERROR is raised if this check | fails. - For conversion to a general access type, the target designated subtype constraints must statically match those of the operand designated subtype, unless the target designated subtype is an unconstrained subtype with discriminants. The same representation | clauses and pragmas must apply to both designated subtypes. | - For conversion to an anonymous access type (see 3.9), as part of a | parameter association or discriminant constraint, a check is made that the access value is not null. CONSTRAINT_ERROR is raised if this check fails. - For conversion of an access parameter (see 3.9) to a general access type, if the scope level of the access parameter is deeper than that of the target type, then a check is made at run time that the scope level of the designated object is no deeper than that of the target type. CONSTRAINT_ERROR is raised if this check fails. [Implementation note: This implies that the scope level must be passed in with an access parameter, in a manner similar to the CONSTRAINED attribute.] - For any other access type conversion, the scope level (see 8.2) of the operand type must not be deeper than that of the target type. [Note: Implicit type conversions are no longer involved with overload resolution. Instead, the formal parameter type is the expected type, and | the actual type must match the expected type according to the operand | matching rules (see 3.3.3). Any implicit conversion is applied after | overload resolution (see 6.4.1).] | Implicit subtype conversions for arrays are generalized to apply in all circumstances where an applicable constraint is present (see RM 4.3.2(4-8)), except for out and in out actual parameters (see 6.4.1). However, an implicit subtype conversion is never applied to an array aggregate with an others choice (see 4.3.2). 4.7. Qualified Expressions The expected type of the operand of a qualified expression is that of the | type mark. | 4.8. Allocators [Note: See 3.9.2 for a discussion of allocators.] 4.9. Static Expressions and Static Subtypes Static expressions involving only the operators of the root numeric types | are evaluated exactly. [Note: This is equivalent to the Ada 83 rule on | static universal expressions.] | The rules for static expressions and static subtypes are generalized to allow more kinds of compile-time-known expressions to be used where static values are required, as follows: - A basic operation may appear in a static expression. - The scalar attributes of statically constrained objects or subtypes are static. - The discriminants of statically constrained objects are static. - The RANGE attribute of a statically-constrained array subtype or object is a static range. - A type conversion is static if the type mark denotes a static subtype and the operand is a static expression. No rounding is performed except on conversion from real to integer, in which case, if the value is exactly between two integers, the result is rounded away from zero. 4.9.1. Statically Matching Constraints and Subtypes [new] A constraint statically matches another constraint if both are static and equal, or both are non-static and originate from the same subtype indication. A subtype statically matches another subtype if both have the same base type, and both are unconstrained or have statically matching constraints. A discrete constraint is statically compatible with a subtype if it statically matches the constraint of the subtype, or if both are static and the constraint is compatible with the subtype. In the case of a discriminant used to define an array bound, the constraint of the discriminant's subtype is also statically compatible with the index subtype if both subtypes are static and no value of the discriminant could cause a constraint error. [Note: This extra rule accommodates the possibility of a null array.] [Note: Statically matching constraints and subtypes are the basis for parameter subtype conformance checking (see 6.3.1).] [Note: The section on Universal Expressions is removed. It is subsumed by 4.5.5 and 4.9.] 5. Ada 9X Statements 5.1. Simple and Compound Statements - Sequences of Statements 5.2. Assignment Statement For an assignment statement whose left-hand side is of a specific type, the | expected type of the right-hand side is that same type. For an assignment | statement whose left-hand side is of the class-wide or universal type for a | class, the expected type of the right-hand side is the root type of the | class. | 5.3. If Statements 5.4. Case Statements 5.5. Loop Statements 5.6. Block Statements 5.7. Exit Statements 5.8. Return Statements 5.9. Goto Statements 6. Ada 9X Subprograms 6.1. Subprogram Declarations The syntax for subprogram declarations is revised to allow ``is <>'', which means that the subprogram is abstract. The syntax for parameter specification is revised to allow for access parameters (see 3.9). subprogram_declaration ::= subprogram_specification [is <>]; parameter_specification ::= identifier_list : mode type_mark [:= expression] | identifier_list : access_definition [:= expression] | An abstract subprogram must not have a body. Only a primitive operation of | a tagged type may be declared abstract. An abstract subprogram may only be | called with class-wide controlling operands (see 3.4.2). | | If a primitive operation of a tagged type is abstract, then the type is an | abstract type (see 3.4.2). When deriving from an abstract type, the | abstract operations must be overridden, either with non-abstract | declarations, or with another abstract subprogram declaration. [Note: | Hence, a tagged type is only abstract if one of its primitive operations is | explicitly declared as abstract.] | A formal parameter specified by an access definition is an in parameter of | an anonymous access type (see 3.9). Such a parameter is called an access | parameter. | 6.2. Formal Parameter Modes Whether an implementation must pass a parameter by copy is determined as follows: - A parameter must be passed by copy if its type is elementary, or is a private type whose full type must be passed by copy. - Otherwise, it is implementation dependent whether a parameter is passed by copy or by reference. [Note: In Ada 83, a program was erroneous if its effect depended on the parameter passing method chosen. In Ada 9X, such a program is non-portable.] An out parameter is a variable that permits both reading and updating. If an out parameter is passed by copy, then any subcomponent that is a discriminant, is of an access type, or has a default initial expression, is copied in prior to the call. It is a bounded error to read a scalar out parameter, or any scalar subcomponent of an out parameter that is not required to be copied in, prior to initializing it. 6.3. Subprogram Bodies A renaming declaration may act as a body for a subprogram. The renaming must be of a subprogram that is subtype conformant with the specification given in the renaming declaration (see 6.3.1). [Note: In accordance with the April '92 ISO WG9 meeting, we have dropped | the proposal allowing a generic instantiation to act as a body. Renaming | may be used to accomplish the same goal, if necessary.] | 6.3.1. Conformance Rules Each subprogram has a calling convention, which is a language name (see 13.9). The default calling convention of a subprogram with a normal Ada body is language ADA. This default may be overridden using pragmas IMPORT, | EXPORT, or LANGUAGE (see 13.9). The calling convention for a predefined or | intrinsic operation is language INTRINSIC. An intrinsic operation is an operation whose specification is defined in Ada, but whose implementation may be incorporated directly into the compiler (that is, there need be no explicit Ada body for the operation). The subprogram specification conformance rules, as well as discriminant part conformance rules, are relaxed to require only the static semantic equivalence defined below as ``full conformance.'' There are four levels of conformance in Ada 9X: Type Conformance requires that two specifications have the same number of parameters (and both have a result if either does) and at each parameter position corresponding parameters (and results, if present) have the same (base) type, or in the case of access parameters (see 3.9), the same designated type. Mode Conformance requires type conformance and that the parameters at each corresponding position have identical modes. For access parameters (see 3.9), the designated subtypes must statically match. Subtype Conformance requires mode conformance. In addition: - The subtypes of the parameters at each parameter position (and results, if any) must statically match (see 4.9.1); - The calling conventions must be the same; - Neither calling convention can be INTRINSIC; - If one is a protected subprogram or entry, then the other must be a protected subprogram or entry, respectively (see 9.7). Full Conformance requires subtype conformance and that the formal parameters at corresponding positions have the same names and conforming default expressions (if any). Two default expressions are said to conform if each primary, operator, or basic operation within one expression has a corresponding primary, operator, or basic operation within the other expression, and, in the case of a primary that is a name, they (statically) denote the same entity. 6.3.2. Inline Expansion of Subprograms 6.4. Subprogram Calls 6.4.1. Parameter Associations The rules for parameter associations are as follows: - The type of the actual parameter must match the formal parameter, according to the operand matching rules (see 3.3.3); - The type of the actual parameter must be convertible to the type of the formal parameter (see 4.6); - For an in or in out parameter that must be passed by copy (see 6.2) the value of the actual parameter is converted (see 4.6) to the subtype of the formal parameter and assigned to it, which may raise CONSTRAINT_ERROR. - After a call that does not propagate an exception, for an in out | or out parameter that must be passed by copy, the value of the formal parameter is converted to the subtype of the actual parameter and assigned to it, which may raise CONSTRAINT_ERROR. - For an in parameter that may be passed by reference, the formal parameter is defined to be a (read-only) conversion (see 4.6) of the actual parameter, to the subtype of the formal parameter. This conversion may raise CONSTRAINT_ERROR. - For an in out or out parameter that may be passed by reference, the value of the actual parameter is checked to ensure that it satisfies the constraints of the subtype of the formal parameter. CONSTRAINT_ERROR is raised if this check fails. The formal parameter is defined to be an (updatable) view of the actual parameter. [Note: As in Ada 83, no constraint check is performed on return for a parameter that may be passed by reference.] As in Ada 83, for a parameter that may be passed by reference, it is implementation dependent whether the value of the formal parameter (which is a view of the actual) is held in a local copy between the call and the return. If an exception occurs, it is therefore implementation dependent whether the actual is updated for such a parameter, when its mode is in out or out. [Note: The rules for parameter associations apply to discriminant constraints as well, where all discriminants are handled like formal in parameters that must be passed by copy. See 3.6.1 and 3.6.2.] 6.4.2. Default Parameters 6.5. Function Subprograms 6.6. Parameter and Result Type Profile - Overloading of Subprograms 6.7. Overloading of Operators The equality operator "=" may be overloaded for any combination of parameter and result types. A corresponding inequality operator "/=" is implicitly declared only if the result type is STANDARD.BOOLEAN. An inequality operator "/=" may be explicitly declared if its result type is not STANDARD.BOOLEAN. 7. Ada 9X Packages 7.1. Package Structure 7.2. Package Specifications and Declarations 7.3. Package Bodies 7.4. Private Type and Deferred Constant Declarations 7.4.1. Private Types The syntax for a private type declaration is augmented to allow the specification of a tagged private type. private_type_declaration ::= type identifier [discriminant_part] is [tagged] [limited] private; A private type is a composite type (see 3.3) outside of the scope of the full type declaration. (In this section a task or protected type declaration is considered a ``full'' type declaration.) If a private type declaration has a discriminant part, then the full type declaration must be a composite or derived type declaration with a fully | conforming discriminant part (see 6.3.1). If a private type declaration includes the modifier tagged, then the full type declaration must be tagged. 7.4.2. Private Extension [new] The declaration of a private type extension of a tagged parent type is allowed in the visible part of a package. A private extension is a tagged composite type, with a private extension part. For each private extension declared in the visible part of a package, a corresponding full type declaration must appear in the private part for a | type derived (directly or indirectly) from the tagged parent type. [Note: | This allows the full type to be defined by deriving from a type produced by | a generic instantiation, or one or more intermediate derivations.] | Unless explicitly overridden within the visible part, the implementations of | the primitive operations inherited from the parent type of a private | extension are determined by the full type declaration and the other | declarations in the private part. Unless a primitive operation of a tagged | private type or private extension is declared as abstract in the visible | part, the full type must not be an abstract type. [Note: These rules imply | that although the specifications of the primitive operations of a private | extension come from the parent type identified in the private extension | definition, the implementations come from the full type. They also imply | that a type is abstract only if some visible operation is explicitly | declared as abstract.] | Example of a private extension: with BASIC_WINDOWS; -- defines tagged type ROOT_WINDOW package EXTENDED_WINDOWS is type LABELED_WINDOW(LENGTH : NATURAL) is new BASIC_WINDOWS.ROOT_WINDOW with private; . . . private type LABELED_WINDOW(LENGTH : NATURAL) is new BASIC_WINDOWS.ROOT_WINDOW with record LABEL : STRING(1..LENGTH); FONT : FONT_ID := 0; end record; end EXTENDED_WINDOWS; 7.4.3. Operations of a Private Type [originally 7.4.2] [Note: As in Ada 83, the attribute T'CONSTRAINED of a private subtype T being true is not the same as T being ``constrained.'' In particular, if the full subtype is an elementary type, T'CONSTRAINED is always true, even if no constraints apply to the subtype. See RM 3.3(4) and RM 7.4.2(10).] 7.4.4. Deferred Constants [originally 7.4.3] A deferred constant declaration, for a constant of any type, is allowed immediately within the visible part of a package. The full constant declaration must appear immediately within the private part of the same package. [Note: In Ada 83, deferred constants were restricted to being of a private type that is declared in the same visible part (see RM 7.4(4)). We are relaxing this restriction.] 7.4.5. Limited Types [originally 7.4.4] [Note: We are still studying the issue of returning a value of a limited | type. This section is our initial attempt to define the semantics of such | an operation, as well as other issues relating to limited types. | Fundamentally, many of these issues revolve around the question: ``what is | the value of an object of a limited type?'' (We will grinningly ignore | opinions that "objects of a limited type have no value.")] | | The value of an inherently aliased (see 3.9.2) object of a limited type | designates that object. [Note: This rule is an adaptation of the Ada 83 | rule for task types, and at least opens the possibility for lessening the | current strong distinction between task objects and tasks.] If a function | returns a value of an inherently aliased limited type, the result designates | the same object designated by the value of the return expression. If the | object is local to the function, it is moved if necessary, so that the | storage for the (moved) object is not reclaimed and the object is not | finalized (see 7.4.6) prior to the caller finishing with the returned value. | | It is a bounded error to return the value of an inherently aliased local | object if the object cannot be moved. Task objects and objects containing | access discriminants cannot be moved. As a result of the bounded error, | PROGRAM_ERROR may be raised, or a value may be returned that designates a | temporary object of the same type that is local to the caller, which is | reclaimed when the caller is finished with the returned value. [Note: This | addresses the issue of returning a task outside of the scope of its master.] | [Note: It is interesting to note that in Ada 83, an object containing a | task subcomponent is considered implicitly referenced as long as the task is | not terminated (see RM 4.8(7)), implying that the task might have access to | the enclosing object, and that the object is inherently aliased. However, | this might appear inconsistent with the note in RM 13.10.1(8) saying that | UNCHECKED_DEALLOCATION of a task object has no effect on the associated | task. Objects containing protected subcomponents will have similar | considerations, particularly when the protected subcomponent is used to | provide a relatively long-lived lock on the enclosing object. We will be | studying these issues further during the revision.] | 7.4.6. Controlled Types [new] A limited tagged type CONTROLLED is defined in package SYSTEM. Any type | derived from this type, directly or indirectly, is called a controlled type. | The tagged type CONTROLLED has two primitive, dispatching operations, | INITIALIZE and FINALIZE, with specifications as follows: | | procedure INITIALIZE(OBJECT : in out CONTROLLED); | | procedure FINALIZE(OBJECT : in out CONTROLLED); | | These operations have null implementations for the type CONTROLLED. They | may be overridden with new implementations for any type derived from | CONTROLLED. | | After a controlled object (including a subcomponent of another object) is | created and has been default initialized, the operation INITIALIZE is | applied to it as the last step in its initialization. If a controlled | object has controlled subcomponents, the INITIALIZE operation is applied to | the controlled subcomponents prior to applying it to the enclosing object. | [Note: This allows the INITIALIZE operation for a composite object to refer | to its subcomponents knowing they have been properly initialized.] For an | object created by an allocator, any subcomponent task activations follow all | INITIALIZE operations. | | Prior to reclaiming the storage for a controlled object (including a | subcomponent of another object), the operation FINALIZE is applied to it. | [Note: This also applies to objects whose storage is reclaimed by | UNCHECKED_DEALLOCATION or automatic storage reclamation.] If a controlled | object has controlled subcomponents, the FINALIZE operation is applied to | the enclosing object prior to applying it to its controlled subcomponents. | [Note: This allows the FINALIZE operation for a composite object to refer to | its subcomponents prior to their being finalized.] | | Upon leaving a declare block, or a procedure, entry, or task body, the | FINALIZE operation is applied to all local controlled objects, including | those in local access collections that have not already been finalized by | UNCHECKED_DEALLOCATION or automatic storage reclamation. For declared | objects and their subcomponents, the FINALIZE operations are applied in the | reverse of the order of the INITIALIZE operations. The FINALIZE operations | are applied after waiting for any local tasks to terminate. [Note: Like | task waiting, the FINALIZE operations are performed whether the scope is | left by reaching the last statement, a return, an exit, a goto, or an abort | or asynchronous transfer.] | | In the case of a function that returns the value of a local controlled | object or local object with a controlled subcomponent (see 7.4.5), the | FINALIZE operation(s) on this object (and possibly others in the same scope) | is (are) deferred until the caller of the function is finished with the | returned value. For all other functions, the FINALIZE operations are | applied upon leaving the function body, as with a procedure. | | Immediately prior to program termination, FINALIZE operations are applied to | library-level controlled objects (including those in library-level access | collections, except those already finalized). This occurs after waiting for | library-level tasks to terminate. [Note: We are considering a pragma that | would apply to a controlled type that would suppress FINALIZE operations for | library-level objects of the type upon program termination. This would be | useful for types whose finalization actions consist of simply reclaiming | global heap storage, when this is already provided automatically by the | environment upon program termination.] | | If any FINALIZE operation propagates an exception, then after completing any | other FINALIZE operations due to be performed, PROGRAM_ERROR is raised at | the point where normal execution would have continued. For example, upon | leaving a block due to a goto statement, the PROGRAM_ERROR would be raised | at the point of the target statement named by the label. | | While performing an INITIALIZE or FINALIZE operation of a controlled type, | abort and asynchronous transfer of control are deferred. [Note: This | ensures that an object is never partially initialized when finalized, or | partially finalized when reclaimed. This also allows, for example, the | result of an allocator performed in an INITIALIZE operation to be stored in | an access object without being interrupted in the middle of the assignment | statement, ensuring that the associated storage can be fully reclaimed by | the FINALIZE operation.] | | [Note: Because CONTROLLED is a library-level type, all controlled types will | also be library-level types (see 3.4.1). This ensures that the FINALIZE | operations may be applied without providing any ``display'' or | ``static-link.'' This simplifies finalization as a result of automatic | storage reclamation, abort, and asynchronous transfer of control.] | 7.5. Example of a Table Management Package 7.6. Example of a Text Handling Package 8. Ada 9X Visibility Rules 8.1. Declarative Region A protected record unit is a declarative region. 8.2. Scope of Declarations Every declaration, every entity declared by a declaration and every object has a scope level, defined as follows: [Note: We intend to simplify this discussion as part of the revision | process.] | All declarations that are local to (i.e. declared immediately within) a particular declarative region have the same scope level. The scope level of a declaration that is local to a package is the same as that of the package. The scope level of a declaration that is local to a subprogram, task unit, protected unit, or block statement is deeper than that of the program unit or block statement. The scope level of a declaration that is local to a generic declaration is defined as for the instance. The scope level of a declaration that is local to a generic body is deeper than that of the generic declaration. The scope level of package STANDARD is called the library-level scope, and entities with this scope level are called library-level entities. The scope level of a derived access type is that of the parent type. The scope level of an access parameter type is that of the corresponding access discriminant or parameter (see 3.6.1 and 3.9). The scope level of any other entity declared by a declaration is that of the declaration. The scope level of an object designated by an access parameter (see 3.9) is that of the object designated by the actual expression initializing the access parameter. The scope level of an object designated by an access discriminant (see 3.6.1) is that of the discriminated object. The scope level of an object designated by any other access value is that of the access type. The scope level of a subcomponent of an object is that of the object. The scope level of a protected operation of an object is that of the object. On a subprogram call, the scope level of a parameter or result of the subprogram being called is deeper than any object declared by or accessible to the caller prior to the call. [Note: This definition ensures that there is no scope check as part of initializing an access parameter (see 3.9 and 4.6). It also ensures that an access discriminant of the result of a function call cannot be used to initialize an access discriminant of an object declared by the caller (see 3.6.1 and 4.6).] [Notes: A package does not introduce a deeper scope level. Other program units do. In order to prevent dangling pointers of various kinds, we have introduced certain scope checks, based on the above definition of scope levels. There are scope checks on derived tagged type declarations (see 3.4.1), on the ACCESS attribute (see 3.9.2), and on type conversion of access types (see 4.6). Most scope checks are done at compile time; the only exception is for conversion of an access parameter (see 3.9) to a general access type (see 4.6).] 8.3. Visibility The declaration of a protected operation of a given protected record type is visible by selection at the place of the selector after the dot of a selected component whose prefix is appropriate for the protected record type. (See RM 8.3(7-12).) For overloadable entities, the definition of homograph is revised as follows: Two declarations of overloadable entities are homographs if they have the same identifier, operator symbol, or character literal, the same number of parameters and results, and if, according to the operand matching rules (see 3.3.3): - the result types (if any) could both match the same specific type; and - for each parameter position, a single specific type could match both formal parameters. [Note: This rule makes two declarations homographs if they are unresolvable even in a context that determines all specific operand and result types.] 8.4. Use Clauses For a child library unit (see 10.1) referenced in a with clause, the declaration of its simple name, which logically occurs within the child part of its parent, is made directly visible by a use clause for the parent package. [Note: In response to the April '92 ISO WG9 meeting, we are proposing two | new kinds of use clauses, to address the visibility of primitive operators | and the accessibility of private declarations of an ancestor library unit.] | For Ada 9X, there are two new kinds of use clauses: | use_clause ::= | ... -- as in Ada 83 | | use type type_mark {, type_mark}; | | use private ancestor_library_package_name | {, ancestor_library_package_name}; | | A type-based use clause is one introduced by the reserved words use type. A | primitive operator of a type is a primitive operation of a type whose | designator is an operator symbol. A type-based use clause makes directly | visible each primitive operator of the type(s) determined by the | type_mark(s), except within the immediate scope of a homograph of the | primitive operator. | | A use clause introduced by the reserved words use private makes the private | declarations of an ancestor library unit package directly accessible within | a child library unit (see 10.1). Outside the scope of such a use-private | clause, it is illegal in a child library unit to reference a declaration | appearing within the private part of an ancestor library unit package. A | use-private clause has no affect on overload resolution; the check for | reference to private declarations is performed after overload resolution. | [Note: This approach is designed to avoid ``Beaujolais'' effects.] | 8.5. Renaming Declarations [Note: A renaming declaration may act as a body for a subprogram. See 6.3.] 8.6. The Package STANDARD 8.7. The Context of Overload Resolution Rather than a preference rule against implicit conversion, as defined in RM 4.6(15), in Ada 9X there is a preference for the primitive operators of the root numeric types root_integer and root_real. The rule is as follows: - In a given context, if two legal interpretations differ only in that one is for a primitive operator of the type root_integer or root_real, and the other is for a corresponding primitive operator for another numeric type, the interpretation using the primitive operator of the root numeric type is preferred. - For an innermost complete context (see RM 8.7(3)), if there is exactly one overall legal interpretation where each constituent's interpretation is the same as or preferred (in the above sense) over those in all other overall legal interpretations, then that one overall legal interpretation is chosen. [Note: It is the intent that this preference rule is more locally enforceable than that of RM 4.6(15). It should also minimize interpretation shifts due to the addition or removal of a use clause (the so called Beaujolais effect).] 9. Ada 9X Tasks and Synchronization 9.1. Task Specifications and Task Bodies A discriminant part is allowed in a task type specification. The discriminants may be referenced within the specification and body of the task using the simple name of the discriminant. In a task type specification, the simple name of a discriminant denotes the discriminant of the task object being elaborated. In a task body, the simple name of a discriminant denotes the discriminant of the task object designating the task currently executing the body. [Note: As with any discriminated type, the discriminants may also be referenced as a selected component of a task object (see RM 4.1.3(4,5)).] task_specification ::= task [type] identifier [discriminant_part] [is {entry_declaration} {representation_clause} [ private {entry_declaration} {representation_clause}] end [task_simple_name]] The first list of entry declarations of a task specification is called the visible part of the task specification. The optional list of entry declarations after the reserved word private is called the private part of the task specification. An entry declared in the private part is not visible outside the task unit. [Note: The task private part has been retained pending further study and | review, to be consistent with protected types and requeue.] | 9.2. Task Types and Task Objects There is no limitation on the use of an out parameter of a task type, since there are no remaining limitations associated with out parameters of a limited type (see 6.2). As in Ada 83, for all parameter modes, if an actual parameter designates a task, the associated formal parameter designates the same task; the same holds for a subcomponent of a parameter (RM 9.2(2)). Expressions appearing within representation clauses and pragmas in a task specification are reevaluated for each object of the task type. Analogous to tagged types (see 3.4.1) a class-wide type SYSTEM.TASK_CLASS is | defined for the task class. By definition, all task types are covered by | SYSTEM.TASK_CLASS. SYSTEM.TASK_CLASS is used for the explicit definition of | class-wide operations on tasks, such as dynamic priority setting operations | (see the Real-Time Systems Annex). | 9.3. Task Execution - Task Activation 9.4. Task Dependence - Termination of Tasks 9.5. Protected Specifications and Protected Bodies [new] [Note: We have adopted the terms ``protected type'' and ``protected object'' | rather than protected record type or object, since protected types are not | considered record types.] | A protected unit consists of a protected specification and a protected body. A protected specification that starts with the reserved words protected type and an identifier declares a protected type and an unconstrained subtype. | The identifier is the name of the subtype. | A protected specification without the reserved word type defines a single protected object. A protected specification with this form of specification is equivalent to the declaration of an anonymous protected type immediately followed by the declaration of an object of the protected type. The protected unit identifier names the object. In the remainder of this chapter, explanations are given in terms of protected type declarations. The corresponding explanations for single protected object declarations follow from the stated equivalence. The value of an object of a protected type designates the protected object, having protected operations and protected components. Each protected specification must have a corresponding protected body. Each protected operation must have a corresponding body; the rules are similar to those for Ada 83 subprogram bodies. The execution of the protected operations are specified by the protected operation bodies given in the body of the protected unit. protected_declaration ::= protected_specification; protected_specification ::= protected [type] identifier [discriminant_part] is { protected_operation_declaration } private { protected_operation_declaration } record component_list end [protected_simple_name] protected_operation_declaration ::= subprogram_declaration | entry_declaration protected_body ::= protected body protected_simple_name is { protected_operation_item } end [protected_simple_name]; protected_operation_item ::= subprogram_declaration | subprogram_body | entry_body 9.6. Protected Types and Protected Objects [new] A protected type is a limited composite type. A protected object is an object whose type is a protected type. For all parameter modes, if an actual parameter is a protected object, the associated formal parameter denotes the same protected object; the same holds for a subcomponent of a parameter. The first list of protected operation declarations of a protected specification is called the visible part of the protected specification. The declarations and component list that appear after the reserved word private make up the private part of the protected specification. The discriminants and the protected operations declared in the visible part of the protected specification are visible by selection outside the protected unit. The non-discriminant data components of a protected object are only visible within the body of the protected unit. They refer to components of the protected object passed as an implicit parameter (see 9.7 below). Expressions appearing within pragmas and default expressions in a protected specification are reevaluated for each object of the protected type. [Note: As for other discriminated types, the discriminants of a protected object may be named with selected component notation anywhere the object may be named.] Example of a Protected Type: protected type COUNTING_SEMAPHORE(INITIAL_COUNT : INTEGER := 1) is -- A Counting Semaphore, -- Acquire = ``P'' operation -- Release = ``V'' operation function COUNT return INTEGER; -- Current count procedure RELEASE; -- Release a resource entry ACQUIRE; -- Acquire a resource, suspend if none private record CURRENT_COUNT : INTEGER := INITIAL_COUNT; -- Count of available resources, default initial value is 1; -- May be negative to represent being in ``debt.'' end COUNTING_SEMAPHORE; protected body COUNTING_SEMAPHORE is function COUNT return INTEGER is -- Return current count of available resources begin return CURRENT_COUNT; end COUNT; procedure RELEASE is -- Release a resource for acquisition by another caller begin -- Increment count of available resources CURRENT_COUNT := CURRENT_COUNT + 1; end RELEASE; entry ACQUIRE when CURRENT_COUNT > 0 is -- Acquire a resource when some are available; -- Suspend if none are available. begin -- Decrement count of available resources CURRENT_COUNT := CURRENT_COUNT - 1; end ACQUIRE; end COUNTING_SEMAPHORE; 9.7. Protected Operations, Entry Calls, and Accept Statements [originally 9.5] Protected objects may have protected operations that are functions, procedures, or entries. [Note: As in Ada 83, a task may only have entries.] Within a protected or task unit, the name of a protected operation is the protected operation's simple name. Outside a protected or task unit, the name of a protected operation declared in the visible part has the form of a selected component. The prefix must be appropriate for (see RM 4.1(6)) the protected or task type that declares the operation. The body of a protected unit may contain function, procedure, and entry bodies corresponding to the operations declared in the protected specification. In addition, the body of a protected unit may contain declarations and bodies for local subprograms. These are not visible outside the protected unit. entry_body ::= entry identifier [(for identifier in discrete_range)] [formal_part] when condition [is [declarative_part] begin sequence_of_statements [exception_handler_part] end [entry_simple_name]]; An entry body specifies a barrier condition for an entry after the reserved word when, and optionally specifies the execution of an operation to be associated with the entry. If the entry is a family, then the name of the family index is provided using the iterator syntax for identifier in discrete_range. The barrier condition is an expression of a boolean type; when the barrier evaluates to TRUE, the entry body may be executed. The barrier may not reference any formal parameters to the entry, but it may reference anything else visible, including the entry family index, the components (including discriminants) of the protected object, the COUNT attribute of an entry of the protected object, or data global to the protected unit. [Note: The restriction against referencing the formal parameters within a barrier expression ensures that all calls in the same entry queue see the same barrier value.] A protected operation takes a protected object as an implicit parameter. This parameter has mode in for protected functions and mode in out for protected procedures and entries. A protected action is a synchronized operation on a protected object. A | call on a protected operation from outside the protected unit is a protected | action. Prior to beginning the protected action, the operation name and the | actual parameters are evaluated. A protected action is synchronized with | other protected actions on the same protected object, as follows: | | - No two protected actions on the same protected object may proceed | concurrently, unless both are the result of function calls. | - As the first step for an action that results from an entry call, | the barrier condition is evaluated. If it yields FALSE, the call is queued, and does not proceed further until the barrier is reevaluated and no longer yields FALSE. - As the final step of a protected action that is not the result of | a function call, if any calls are queued, the barrier conditions are reevaluated. If the barrier of an entry with a queued call no longer evaluates to FALSE, one call on such a queue is selected as the next protected action to be performed on the protected object. | If more than one call is eligible, an implementation-defined rule is used to select among them. The process of reevaluating the barrier conditions to select the next action | is called servicing the entry queues. By default, the calls on an entry queue are serviced in order of arrival. Other orders may be specified by a language-defined or implementation-defined pragma (see RT:QUEUE-POLICY:SECT). The language does not specify which task services the entry queues, and executes the entry body of the selected action. | If the evaluation of a barrier condition propagates an exception, | PROGRAM_ERROR is propagated to all callers currently on any entry queue of | the protected object. | An implementation need not reevaluate a barrier condition if its associated queue is empty, or if the evaluation of a prior barrier allows a call to be selected. A barrier condition also need not be reevaluated if the variables referenced by it were not altered by a protected action on the protected | object since the last evaluation of the barrier. [Note: These rules allow certain simplifications and optimizations in the implementation. The second rule implies that barrier conditions should not reference variables altered outside of the protected unit.] The value of the COUNT attribute of an entry of a protected object is the number of calls in its entry queue. The COUNT attribute is only available within the body of the protected unit. When an entry call is cancelled (see 9.9.2), the value of the COUNT attribute will still include this call until either it is removed from the queue, or the call is selected. If a cancelled call is selected before it is removed from the queue, the call will be ignored. Removing a cancelled call from its queue is a protected action, and hence | cannot occur during any other protected action. Upon completing the | removal, the entry queues whose barriers depend on the COUNT attribute are serviced. A protected action may include a call on a protected subprogram where the | target object is identified implicitly to be the current protected object. | In this case, a new protected action is not started; instead, the call is | performed as part of the current action. [Note: the parameter mode of the | implicit protected object parameter precludes a protected function from calling a protected procedure in this way.] A protected action may include a call on a protected subprogram where the | protected object is specified as the prefix. In this case, a new protected | action is performed on the specified protected object, as described above. | The following are defined to be potentially suspending operations: - a select statement; - an accept statement; - an entry call; - a delay statement; - a task creation; - an abort statement; - a call on a subprogram in a language-defined I/O package; - a call on an implementation-defined subprogram that is defined to | potentially suspend the calling task. | It is a bounded error for a protected action to directly or indirectly | perform a potentially suspending operation. It is also a bounded error for a protected action on a protected object to call, directly or indirectly, a | protected subprogram with a prefix identifying an object that is the same protected object. In both cases, the bounded error may eventually result in deadlock, raise PROGRAM_ERROR (immediately or as soon as the error is detected), or go undetected. To ensure the error is bounded, an implementation that does not | detect all such errors, and allows a second protected action to be | improperly performed in the middle of the current protected action, must | assume that the state of the protected object is updated by any operation that might lead to such an undetected error (such as a call out from the protected type). [Note: Some of the above ``potentially suspending'' operations are not directly suspending. However, they are still treated as errors because requiring them to be supported from within a protected operation was felt to impose an undesirable implementation burden.] 9.7.1. Requeue Statements [new] A requeue statement may be used to complete the execution of an entry body or accept statement, and at the same time commence a new entry call. In effect, the original entry call is being redirected to a new entry. requeue_statement ::= requeue entry_name [with abort]; A requeue statement is only allowed within an entry body or an accept statement, and is associated with the innermost such construct; a requeue statement is not allowed within a program unit body nested within this entry body or accept statement. A requeue within an entry body may only be to an entry of a protected object. A requeue within an accept statement may be to an entry of a task or protected object. The entry named by the requeue statement must either have no parameters, or be subtype conformant (see 6.3.1) with the parameter profile of the innermost enclosing entry body or accept statement. [Note: The presence or absence of a family index plays no part in the conformance check. The family index, if any, is considered part of the entry name, not one of its parameters.] The execution of a requeue statement proceeds by first evaluating the entry name, including any prefix identifying the target task or protected object. If the target object is identified implicitly as being the current task or protected object, the call is simply added to that entry's queue, to be selected later when the entry is serviced. If the target object is specified explicitly in the entry name, then the requeue is handled like a normal entry call up until the point when the requeued call is complete or queued. Having queued or completed the requeued call, the entry body or accept statement containing the requeue statement is exited. A requeued entry's formal parameters are handled as follows: - If the new entry has formal parameters, then the values of these formal parameters will be initialized from the values of the corresponding formal parameters of the current entry at the time of the requeue. - If the new entry does not have formal parameters, then the values of the formal parameters of mode in out or out of the current entry that were passed by copy are retained for later copy back and constraint check after completing the new entry call. [Note: This treatment of formal parameters as part of a requeue will normally not require any special action at run-time, since the parameters to an entry call will normally be kept in a parameter block allocated by the original caller.] If the requeue statement includes the reserved words with abort then abort is not deferred while the task is waiting on the new entry queue. Otherwise, abort remains deferred during the requeuing. See 9.12 for a further discussion of abort. 9.8. Delay Statements, Duration, and Time [originally 9.6] The syntax for the delay statement is extended as follows: delay_statement ::= delay until simple_expression; | delay simple_expression; The first form of the delay statement delays the task until the specified time is reached. The type of the time expression must be either CALENDAR.TIME, or else some time type as allowed by Annex RT:ALL. If the time has already passed, the task is not suspended. The second form of the delay statement delays the task for the specified duration. The type of the duration expression must be STANDARD.DURATION. The task is not suspended if the duration is less than or equal to zero. [Note: Even if the task is not suspended, a delay statement is alw