!standard 9.5(17/3) 18-05-07 AI12-0064-2/16 !standard 9.5.1(8) !standard 9.5.1(9) !standard 9.5.1(10) !standard 9.5.1(11) !standard 9.5.1(12) !standard 9.5.1(13) !standard 9.5.1(14) !standard 9.5.1(15) !standard 9.5.1(16) !standard 9.5.1(18) !standard 9.5.1(22.1/2) !standard 3.10.2(32/3) !standard 4.6(24.21/4) !standard 4.9(8) !standard 13.1.1(17/3) !standard 13.13.2(37/1) !class Amendment 15-10-17 !status Amendment 1-2012 17-11-21 !status WG9 Approved 18-06-22 !status ARG Approved 6-0-2 17-10-15 !status work item 15-12-18 !status received 15-10-17 !priority Medium !difficulty Medium !subject Nonblocking subprograms !summary Aspect and attribute Nonblocking are added. !problem During a protected action, it is a bounded error to invoke an operation that is potentially blocking. There is currently no mechanism (other than a comment) to specify that a given subprogram is intended to be safely callable during a protected action (i.e., that the subprogram will not invoke an operation that is potentially blocking). This seems like a useful part of a subprogram's "contract" that should be (optionally) specifiable at the point of a subprogram's declaration. !proposal Add the aspect Nonblocking and the attribute Nonblocking to Ada. These allow specifying and querying the blocking status of a subprogram. If a subprogram is declared to be nonblocking, the Ada compiler will verify that it does not execute any potentially blocking operations (other than deadlocking operations). !wording [Editor's note: Individual rule changes scattered throughout the Standard follow this primary definition.] Add after 9.5(17/3): Static Semantics An expression is *nonblocking-static* if it is one of the following: * a static expression; * a Nonblocking attribute reference; * a call to a predefined boolean logical operator /and/ where each operand is nonblocking-static; * an /and then/ short-circuit control form where each operand is nonblocking-static; * a parenthesized nonblocking-static expression. [Editor's note: This wording is intended to parallel the definition of predicate-static expression (from 3.2.4(15-22/3)). However, we only allow combining expressions with "and" or "and then", as this is the only useful case. (Other combinations mismatch with the underlying Legality Rules.)] AARM Reason: We define the term "nonblocking-static expression" so that nonblocking attribute references can be used to define the value of other nonblocking aspects, but we don't allow anything else with a value not known at compile-time. For a program unit, task entry, formal package, formal subprogram, formal object of an anonymous access-to-subprogram type, enumeration literal, and for a type (including a formal type), the following language-defined operational aspect is defined: Nonblocking This aspect specifies the blocking restriction for the entity; it shall be specified by an expression, called a *nonblocking expression*. If directly specified, the aspect_definition shall be a nonblocking-static expression. The expected type for the expression is the predefined type Boolean. [Redundant: The aspect_definition can be omitted from the specification of this aspect; in that case the nonblocking expression for the entity is the enumeration literal True.] AARM Proof: 13.1.1 allows omitting the aspect expression for any aspect with type Boolean; we take advantage of that here. [Editor's note: 13.1.1(15/3) doesn't say that it applies only to boolean-valued aspects - we take advantage of the vagueness here. The basic outline of the wording is the same as used for preconditions.] [Editor's 2nd note: One difference with preconditions is that we specify that the type is Boolean, not "any boolean type". We did this because we have defined nonblocking attributes, and having attributes with a different type than the aspect is weird, while attributes with "any boolean type" is weirder. ] The Nonblocking aspect may be specified for all entities for which it is defined, except for protected operations and task entries. In particular, Nonblocking may be specified for generic formal parameters. [Editor's note: The explicit mention of generic formal parameters here is to make it clear that such specification is intended; 13.1(9.4/5) does not apply to aspect Nonblocking. This is the "unless otherwise specified" of that rule.] AARM Ramification: The Nonblocking aspect cannot be specified for predefined operators or enumeration literals but we don't need to mention that above. One would have to declare a subprogram in order to specify the aspect, but that makes a user-defined subprogram which is itself not a predefined operator or an enumeration literal. When the nonblocking expression is static for an entity, the expression is evaluated to produce a static value for the aspect. When aspect Nonblocking is statically False for an entity, the entity might contain a potentially blocking operation; such an entity *allows blocking*. If the aspect is statically True for an entity, the entity is said to be *nonblocking*. AARM Discussion: We have to allow the aspect to be described as an expression inside of generic units, where the actual value of the aspect in an instance could be determined by the aspect of one or more actuals. Our intent is that the expression is always a static expression outside of any generic unit, and that in such contexts it is treated more like a static value than an expression. AARM Ramification: specifying Nonblocking as False imposes no restrictions. Specifying Nonblocking as True imposes additional compile-time checks to prevent blocking, but does not prevent deadlock. A pragma Detect_Blocking can be used to ensure that Program_Error is raised in a deadlock situation. For a generic instantiation and entities declared within such an instance, the aspect is determined by the nonblocking expression for the corresponding entity of the generic unit, with any Nonblocking attributes of the generic formal parameters replaced by the appropriate nonblocking expression of the corresponding actual parameters. If the aspect is directly specified for an instance, the specified expression shall be static and have the same value as the nonblocking expression of the instance (after replacement). AARM Reason: We want to allow confirming aspects for instances, but nothing else. The Legality Rules of the generic body were checked assuming the nonblocking expression of the generic unit, and if that is changed, the instance body might make calls that allow blocking in subprograms that are nonblocking. AARM Ramification: If the nonblocking expression of the instance is not static (if the instance is itself inside of a generic unit), then the Nonblocking aspect cannot be specified for the instance. [Editor's note: I've made the re-evaluation and re-checking of the Nonblocking aspect explicit; while it follows from "normal" generic instance processing, it's unusual enough to be worth spelling out.] [Editor's 2nd note: I tried to use the term "confirming" here, but confirming is not defined for operational aspects (13.1(18.2/3) only applies to representation aspects). And then we would probably have had to explain that for non-static aspect expressions, that "conforming is confirming". :-)] [Editor's 3rd note: We originally had a mechanism for allowing a conforming expression to be given here in case the aspect expression is not static, but the description seemed too complex for a feature that is "nice-to-have" at best. We could have allowed no specification at all for instances, but it seems useful for the reader of a instance to know that the instance is nonblocking without having to look up the definition of the generic unit and repeat any substitutions.] For a (protected or task) entry, the Nonblocking aspect is the Boolean literal False. AARM Reason: An entry can be renamed as a procedure, so the value of the aspect has to be well-defined (as the attribute can be applied to a procedure). We do not want a nonblocking subprogram to be able to call an entry, no matter how it occurs, so the value ought to be False. Moreover, we do not want a subprogram that renames an entry to be able to override a nonblocking subprogram. We could have used individual rules for these cases, but there were already many of them, and this solution avoids the need for extra rules. For an enumeration literal, the Nonblocking aspect is the Boolean literal True. AARM Reason: Enumeration literals can be renamed as functions, and passed to generic formal functions, so we need to define the value of the aspect to ensure the other rules are meaningful. For a predefined operator of an elementary type, the Nonblocking aspect is the Boolean literal True. For a predefined operator of a composite type, the Nonblocking aspect of the operator is the same as the Nonblocking aspect for the type. AARM Reason: Predefined operators of elementary types can never include any potentially blocking operations, so we want them to declare that. Record equality can be composed of operations including user-defined "=" operators, which might allow blocking. Array equality might use some record equality. So we have to have the possibility of allowing blocking for them. We don't just copy the Nonblocking aspect of the type in every case, as someone could declare an elementary type to allow blocking, but we don't want to have to worry about generic matching, so the operators of elementary types are handled separately. In addition, aspects of subprograms can be view-specific, while aspects of types cannot be view specific (see 13.1.1); thus in order to handle private types completed by elementary types, we need to have this rule apply to the operators, not the types. AARM Ramification: It's not possible to specify the nonblocking expression of a predefined operator; if an operator is declared in order to do that, it is no longer predefined. For a dereference of an access-to-subprogram type, the Nonblocking aspect of the designated subprogram is that of the access-to-subprogram type. [Redundant: For a full type declaration that has a partial view, the aspect is the same as that of the partial view.] AARM Proof: Type aspects are never view-specific; they always have the same value for all views. This is formally stated in 13.1. For an inherited primitive dispatching subprogram that is null or abstract, the subprogram is nonblocking if and only if a corresponding subprogram of at least one ancestor is nonblocking. For any other inherited subprogram, it is nonblocking if and only if the corresponding subprogram of the parent is nonblocking. [Editor's note: One cannot "directly specify" an aspect for any inherited subprogram, so this paragraph has a different form than the rest.] Unless directly specified, overridings of dispatching operations inherit this aspect. Unless directly specified, for a formal type, formal package, or formal subprogram, the Nonblocking aspect is that of the actual type, package, or subprogram. AARM Reason: This means that Nonblocking legality checking for the actual parameters of the instance is only necessary when the aspect is explicitly specified for the formal type. Unless directly specified, for a derived type, the Nonblocking aspect is that of the parent type. AARM Discussion: The expressions that can be specified for a derived type are limited by a Legality Rule, see below. Unless directly specified, for any other program unit, type, or formal object, the Nonblocking aspect of the entity is determined by the Nonblocking aspect for the innermost program unit enclosing the entity. [Editor's note: Formal objects are here since objects don't have the aspect in general, only in this specific case.] If not specified for a library unit, the nonblocking expression is the Boolean literal True if the library unit is declared pure and is not a generic unit, or the Boolean literal False otherwise. [Editor's note: Legality Rules follow all of these other Static Semantics definitions.] For a prefix S that denotes a subprogram (including a formal subprogram): S'Nonblocking Denotes whether subprogram S is considered nonblocking; the type of this attribute is the predefined type Boolean. The prefix S shall statically denote a subprogram. AARM Ramification: The evaluation of the prefix S will have no effect, which is necessary for S'Nonblocking to be static. For the intended use in aspect specifications, we don't want any evaluation, as it would happen at some freezing point. S'Nonblocking represents the nonblocking expression of S; evaluation of S'Nonblocking evaluates that expression. [Editor's note: All of these attributes are not allowed to be used outside of a generic unit if the prefix is that of an entity declared within the generic unit; when the prefix is that of an entity declared within a generic unit, the nonblocking value may depend on the actuals and thus only has a defined static value in an instance (that is outside of any generic). This is given in the Legality Rules below.] For a prefix P that denotes a package (including a formal package): P'Nonblocking Denotes whether package P is considered nonblocking; the type of this attribute is the predefined type Boolean. P'Nonblocking represents the nonblocking expression of P; evaluation of P'Nonblocking evaluates that expression. For a prefix S that denotes a subtype (including formal subtypes): S'Nonblocking Denotes whether predefined operators (and in the case of access-to-subprogram subtypes) a subprogram designated by a value of type S are considered nonblocking; the type of this attribute is the predefined type Boolean. S'Nonblocking represents the nonblocking expression of S; evaluation of S'Nonblocking evaluates that expression. [Editor's note: The following is moved from 9.5.1, including the AARM notes with minimal changes. The entry_call_statement rule had been previously identified as needing a change (it's really broken, having nothing specifically to do with this AI).] The following are defined to be *potentially blocking* operations: AARM Reason: The primary purpose of these rules is to define what operations are not allowed in a protected operation (blocking is not allowed). Some of these operations are not directly blocking. However, they are still treated as potentially blocking, because allowing them in a protected action might impose an undesirable implementation burden. * a select_statement; * an accept_statement; * an entry_call_statement, or a call on a procedure that renames or is implemented by an entry; * a delay_statement; * an abort_statement; * task creation or activation; * during a protected action, an external call on a protected subprogram (or an external requeue) with the same target object as that of the protected action; AARM Reason: This is really a deadlocking call, rather than a blocking call, but we include it in this list for simplicity. * a call on a subprogram whose body contains a potentially blocking operation. AARM Reason: This allows an implementation to check and raise Program_Error as soon as a subprogram is called, rather than waiting to find out whether it actually reaches the potentially blocking operation. [Editor's notes: End mostly unchanged text. I considered trying to unify Nonblocking and potentially blocking further, but that seemed messy and error-prone. One could imagine replacing the last rule with "a call on a subprogram with Nonblocking = False", but that would expose a lot of existing code to a Bounded Error (since the default for Nonblocking is False, and that has to be the case for compatibility).] If a language-defined subprogram allows blocking, then a call on the subprogram is a potentially blocking operation. [Editor's note: This is what remains of 9.5.1(18). The old definition should be reflected in the aspect values for language-defined routines; see the discussion of language-defined units below.] Legality Rules A nonblocking program unit shall not contain, other than within nested units with Nonblocking specified as statically False, a call on a callable entity for which the Nonblocking aspect is statically False, nor shall it contain any of the following: * a select_statement; * an accept_statement; * a delay_statement; * an abort_statement; * task creation or activation. AARM Ramification: Implicit calls for finalization, storage pools, and the like are covered by the above prohibition. The rules above say "a call", not "an explicit call". Such calls are considered statically bound when that is possible; that is, when the controlling object has a known specific type (even if the actual implementation uses dispatching). AARM Discussion: We don't need to specially worry about subprograms of limited interfaces that are implemented by entries, as any such subprogram necessarily has the value statically False for the Nonblocking aspect, and thus is already covered by the prohibition against calling such subprograms. Similarly, we don't need to worry specially about entry calls, as they will be detected by the prohibition against calls to entities with the Nonblocking aspect False. End AARM Discussion. For the purposes of the above rule, an entry_body is considered nonblocking if the immediately enclosing protected unit is nonblocking. AARM Reason: An entry always allows blocking (by rule); but we want to be able to compile-time check for most violations of prohibition against potentially blocking operations in a protected action (see 9.5.1). We do that by using the nonblocking status of the protected unit as the controlling factor, and enforce that by not allowing the specification of the Nonblocking aspect for any protected operation. A subprogram shall be nonblocking if it overrides a nonblocking dispatching operation. An entry shall not implement a nonblocking procedure. If an inherited dispatching subprogram allows blocking, then the corresponding subprogram of each ancestor shall allow blocking. AARM Discussion: Rules elsewhere in the standard (4.6 and 3.10.2) ensure that access-to-subprogram conversion and the Access attribute enforce nonblocking. [Editor's note: These rules are given later in this AI.] AARM Ramification: A nonblocking subprogram can override one that allows blocking, but the reverse is illegal. Thus one can declare a Finalize subprogram to be nonblocking, even though it overrides a routine that allows blocking. (This works because a nonblocking subprogram allows a strict subset of the operations allowed in allows blocking subprograms, so calling such a subprogram as if it allows blocking -- as is necessary in a dispatching call -- is harmless.) It is illegal to specify aspect Nonblocking for the full view of a type that has a partial view. AARM Ramification: The aspect should be specified on the partial view for such a type. This is necessary to prevent the predefined equality operator from being nonblocking in the partial view and allowing blocking in the full view. Aspect Nonblocking shall be specified for a derived type only if it fully conforms to the nonblocking expression of the ancestor type or if it is specified to have the Boolean literal True. AARM Reason: Boolean-valued aspects have a similar rule (see 13.1.1), we want this one to work similarly. [Editor's note: The rule in question is 13.1.1(18.1/4).] If aspect Nonblocking is specified for an entity that is not a generic unit or declared inside of a generic unit, the aspect_definition shall be a static expression. If the prefix of a Nonblocking attribute reference denotes a generic unit G, the reference shall occur within the declarative region of G. AARM Reason: We want the value of Nonblocking attributes to be static so long as they occur outside of any generic unit. The Nonblocking aspect of a generic unit will often depend on the actual parameters of the unit, so it cannot be static (or have any well-defined value). We need this latter rule in case the attribute of a generic is used outside of the generic. Note that the previous rule makes it illegal to use such an attribute to specify aspect Nonblocking outside of a generic, but we don't want to allow any other uses since it does not have a known value until instantiated. AARM Ramification: This rule does not apply to instances of generic units and entities declared within them. [Editor's note: We don't need to talk about entities "declared within a generic unit G", as those aren't visible anyway, and thus can't be used as a prefix of an attribute. If someone finds a way to do that, we'll need to add that to this rule.] The predefined equality operator for a composite type is illegal if it is nonblocking and, for a record type, it is not overridden by a primitive equality operator, and: * for a record type, the parent primitive "=" allows blocking; or * any component that has a record type that has a primitive "=" that allows blocking; or * any component that has a non-record type that has a predefined "=" that allows blocking. AARM Ramification: This applies to both record and array "=". This check occurs when the equality operator is declared, so this rule effectively makes the type illegal if the rule is violated. End AARM Ramification. AARM Reason: We don't need to check this when the operator is overridden for a record type, as the body of the new definition of equality will enforce the rules, and there is no case where the predefined operator will re-emerge. We do have to check this for array types even if the operator is overridden, as the predefined operator will re-emerge in generics and record equality. In a generic instantiation (after replacement in the nonblocking expressions by values of the actuals as described previously): * the actual subprogram corresponding to a nonblocking formal subprogram shall be nonblocking Redundant[(an actual that is an entry is not permitted in this case)]; * the actual type corresponding to a nonblocking formal private, derived, array, or access-to-subprogram type shall be nonblocking; AARM Ramification: We do not require matching for formal scalar or access-to-object types, as their predefined operators are always nonblocking (and they re-emerge in the generic unit) -- the nonblocking status of the type has no impact. * the actual object corresponding to a formal object of a nonblocking access-to-subprogram type shall be of a nonblocking access-to-subprogram type; * the actual instance corresponding to a nonblocking formal package shall be nonblocking. In addition to the places where Legality Rules normally apply (see 12.3), the above rules also apply in the private part of an instance of a generic unit. AARM Ramification: For a generic formal parameter to be nonblocking (thus, for these rules to apply), it has to explicitly specify aspect Nonblocking to be True. In particular, these rules do not apply when it specifies aspect Nonblocking to be an expression involving attribute Nonblocking of a generic formal parameter. However, in such a case, these rules do apply in the instance of the specification of the generic unit (the normal re-checking is needed). For instance, the body of an expression function might make a prohibited call. A program unit P declared inside of a generic unit but not in a generic body or that is a generic specification not declared in a generic unit is considered nonblocking for the purposes of checking the restrictions on a nonblocking unit only if the value of its Nonblocking aspect is statically True. For the purposes of checks in P, a call to a subprogram is considered nonblocking unless the value of its Nonblocking aspect is statically False. AARM Reason: This is a typical "assume-the-best" rule. We only make checks if we know the nonblocking status of both P and the called subprogram. All other checks will be performed when the generic unit is instantiated. We used the awkward "inside of a generic unit but not in a generic body" so that a generic specification declared inside of a generic body uses the following "assume-the-worst" rule. A program unit P declared inside of a generic body or that is a generic body is considered nonblocking for the purposes of checking the restrictions on a nonblocking unit unless the value of its Nonblocking aspect is statically False. For the purposes of checks in P, a call to a subprogram is considered to allow blocking unless: * the value of its Nonblocking aspect is statically True, or * its nonblocking expression (that is, Nonblocking aspect) conforms exactly to that of P, or conforms to some part of the nonblocking expression of P that is combined with the remainder of the nonblocking expression of P by one or more "and" or "and then" operations. AARM Ramification: That is, if the aspect of the program unit is specified (directly or via inheritance) with any non-static Nonblocking aspects, it is considered to be a nonblocking program unit for the purposes of making checks. This is a typical "assume-the-worst" rule. AARM Reason: The second part allows calls on subprograms with Nonblocking aspects of Formal'Nonblocking, so long as the Nonblocking aspect of P is some formula that contains Formal'Nonblocking combined with "and". This ensures that P will always allow blocking if the actual for Formal turns out to allow blocking. Without this rule, we'd allow calls on formals in any body subprogram, even if the subprogram did not include the formal in its Nonblocking aspect. For instance: procedure Blah with Formal1'Blocking is begin Formal2; end Blah; If Formal1 is nonblocking and Formal2 allows blocking, then we'd have a nonblocking routine calling a routine that might block. That has to be prevented as this is "assume-the-worst" checking. End AARM Reason. Modify 9.5.1(8): During a protected action, it is a bounded error to invoke an operation that is potentially blocking.[ The following are defined to be potentially blocking operations:] [Editor's note: This is no longer a definition for potentially blocking.] Delete 9.5.1(9-16, 18) and the associated AARM notes. Replace note 9.5.1(22.1/2) with: The aspect Nonblocking can be specified True on the definition of a protected unit in order to reject most attempts to use potentially blocking operations within the protected unit (see 9.5). The pragma Detect_Blocking may be used to ensure that any remaining executions of potentially blocking operations during a protected action raise Program_Error. See H.5. AARM Discussion: The deadlock case cannot be detected at compile-time, so pragma Detect_Blocking is needed to give it consistent behavior. [Editor's note: I decided to ignore the possibility of doing this checking at runtime with just pragma Detect_Blocking -- why would anyone want to take the risk of an unexpected Program_Error if compile-time checks are available?] Modify 3.10.2(32/3): [Part of the definition of the Access attribute for subprograms] ... The accessibility level of P shall not be statically deeper than that of S. {If S is nonblocking, P shall be nonblocking. }In addition to the places where Legality Rules normally apply (see 12.3), {these rules apply}[this rule applies] also in the private part of an instance of a generic unit. Add after 4.6(24.21/4): [Type conversion Legality Rules for access-to-subprogram types] * If the target type is nonblocking, the operand type shall be nonblocking. Add after 4.9(8): * an attribute_reference whose prefix denotes a non-generic entity that is not declared in a generic unit, and whose attribute_designator is Nonblocking; [Editor's note: Any generic unit or anything declared inside of a generic unit makes Nonblocking nonstatic. We want non-generic Nonblocking to be static so that it can be used freely in defining the Nonblocking aspect for other entities, and so that such uses don't affect the generic body assume-the-worst rules.] Modify the AARM Note 13.1(9.d/3): ...most aspects do not need this complexity[ (including all language-defined aspects as of this writing)], we avoid the complexity... [Editor's note: This and the next couple of changes are needed as Nonblocking can be specified on generic formal parameters, and it surely is language-defined. In this particular case, the rule itself is fine (it says "Unless otherwise specified...").] Remove generic_formal_parameter_declaration from the list in 13.1.1(17/5). [Editor's note: Nonblocking is allowed there, of course, so the statement will be clearly False. Moreover, 13.1(9.4/5) already says the same thing, with the needed "unless otherwise specified", so we don't need to mention formals here at all.] Modify the AARM Note 13.1.1(17.a/3): Implementation-defined aspects can be allowed on these, of course; the implementation will need to define the semantics. In {addition}[particular], {the language does not define default aspect matching rules for generic formals; only the handful of aspects allowed on formals have such rules. Therefore,} the implementation will need to define actual [type] matching rules for any aspects allowed on formal types[; there are no default matching rules defined by the language]. Add after 13.13.2(37/1): The aspect Nonblocking is the Boolean literal False for the default implementations of stream-oriented attributes. AARM Reason: The underlying Read/Write operations are called via dispatching calls. Since we cannot afford any incompatibility with existing Ada code, the stream operations allow blocking. Thus the stream-oriented attributes must allow blocking as well. Wording for definition of language-defined packages and subprograms is given in AI12-0064-2. These are just appropriate aspect clauses, and in a few cases, the deletion of the English text that says something is potentially blocking. If a language-defined package needs to add Nonblocking, any pragma will also be changed to the aspect form at the same time. [Lengthy Editor's note: (Preserved here as it was part of the approved AI.) We intend that language-defined subprograms are nonblocking unless this Standard says otherwise. Specifically, 9.5.1(18) said (before we deleted it above): Certain language-defined subprograms are potentially blocking. In particular, the subprograms of the language-defined input-output packages that manipulate files (implicitly or explicitly) are potentially blocking. Other potentially blocking subprograms are identified where they are defined. When not specified as potentially blocking, a language-defined subprogram is nonblocking. Non-generic units that are pure are automatically nonblocking as specified in 9.5 (these are noted below). Other units should explicitly have aspect Nonblocking specified. We'll handle the containers in AI12-0112-1 (the AI that defines preconditions for the container operations); it probably makes the most sense to add all of the contracts at once for those. The entire list of non-container units is: Ada - A.2 - Pure Ada.Assertions 11.4.2 - Pure Ada.Asynchronous_Task_Control D.11 - Nonblocking => True Ada.Calendar 9.6 - Nonblocking => True Ada.Calendar.Arithmetic 9.6.1 - Nonblocking => True Ada.Calendar.Formatting 9.6.1 - Nonblocking => True Ada.Calendar.Time_Zones 9.6.1 - Nonblocking => True Ada.Characters A.3.1 - Pure Ada.Conversions A.3.4 - Pure Ada.Handling A.3.2 - Pure Ada.Latin_1 A.3.3 - Pure Ada.Command_Line A.15 - Nonblocking => True Ada.Complex_Text_IO G.1.3 - Nonblocking => False (** String routines) Ada.Decimal F.2 - Pure Ada.Direct_IO A.8.4 - Nonblocking => False (I/O) Ada.Directories A.16 - Nonblocking => False (I/O) - Full_Name through Compose should have Nonblocking => True (as they are just string manipulation routines). Ada.Directories.Hierarchical_File_Names A.16.1 - Nonblocking => True (these are all string manipulation routines). Ada.Directories.Information A.16 - (**** Impl def) Ada.Dispatching D.2.1 - Nonblocking => False (For Yield by the second sentence of D.2.1(7/3), which should be deleted. There are no other subprograms here.) Ada.Dispatching.EDF D.2.6 - Nonblocking => True - Delay_Until_and_Set_Deadline has Nonblocking => False. -- (This wording is missing from the RM, -- so we don't have to delete it.) (***** AB.) Ada.Dispatching.Non_Preemptive D.2.4 - Nonblocking => True -- AARM Note D.2.4(2.b/3) confirms this for Yield_to_Higher. -- Yield_to_Same_or_Higher is a rename, and gets the value from the original routine. Ada.Dispatching.Round_Robin D.2.5 - Nonblocking => True (***** AB.) Ada.Dynamic_Priorities D.5.1 - Nonblocking => True (***** AB.) Ada.Environment_Variables A.17 - Nonblocking => True Ada.Exceptions 11.4.1 - Nonblocking => True Ada.Execution_Time D.14 - Nonblocking => True Ada.Execution_Time.Group_Budgets D.14.2 - Nonblocking => True Ada.Execution_Time.Interrupts D.14.3 - Nonblocking => True Ada.Execution_Time.Timers D.14.1 - Nonblocking => True Ada.Finalization 7.6 - Nonblocking => False (*** user overriding) Ada.Float_Text_IO A.10.9 - Nonblocking => False (** String routines) Ada.Float_Wide_Text_IO A.11 - Nonblocking => False (** String routines) Ada.Float_Wide_Wide_Text_IO A.11 - Nonblocking => False (** String routines) Ada.Integer_Text_IO A.10.8 - Nonblocking => False (** String routines) Ada.Integer_Wide_Text_IO A.11 - Nonblocking => False (** String routines) Ada.Integer_Wide_Wide_Text_IO A.11 - Nonblocking => False (** String routines) Ada.Interrupts C.3.2 - Nonblocking => True Ada.Interrupts.Names C.3.2 - (**** Impl def) Ada.IO_Exceptions A.13 - Pure Ada.Iterator_Interfaces 5.5.1 - Nonblocking => False (this declares interfaces used elsewhere, and we have to allow blocking in the -- implemented routines. This is annoying; we may have to make a separate nonblocking version for the parallel stuff) Ada.Locales A.19 - Nonblocking => True Ada.Numerics A.5 - Pure Ada.Numerics.Complex_Arrays G.3.2 - Pure Ada.Numerics.Complex_Elementary_Functions G.1.2 - Pure Ada.Numerics.Complex_Types G.1.1 - Pure Ada.Numerics.Discrete_Random A.5.2 - Nonblocking => True Ada.Numerics.Elementary_Functions A.5.1 - Pure Ada.Numerics.Float_Random A.5.2 - Nonblocking => True Ada.Numerics.Generic_Complex_Arrays G.3.2 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Numerics.Generic_Complex_Elementary_Functions G.1.2 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Numerics.Generic_Complex_Types G.1.1 - Nonblocking => True (Pure but generic) Ada.Numerics.Generic_Elementary_Functions A.5.1 - Nonblocking => True (Pure but generic) Ada.Numerics.Generic_Real_Arrays G.3.1 - Nonblocking => True (Pure but generic) Ada.Numerics.Real_Arrays G.3.1 - Pure Ada.Real_Time D.8 - Nonblocking => True Ada.Real_Time.Timing_Events D.15 - Nonblocking => True (confirmed by note D.15(48/2)). Ada.Sequential_IO A.8.1 - Nonblocking => False (I/O) Ada.Storage_IO A.9 - Nonblocking => False (I/O) Ada.Streams 13.13.1 - Nonblocking => False (*** user overriding) Ada.Streams.Stream_IO A.12.1 - Nonblocking => False (I/O) Ada.Strings A.4.1 - Pure Ada.Strings.Bounded A.4.4 - Nonblocking => True Ada.Strings.Bounded.Equal_Case_Insensitive A.4.10 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Bounded.Hash A.4.9 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Bounded.Hash_Case_Insensitive A.4.9 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Bounded.Less_Case_Insensitive A.4.10 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Fixed A.4.3 - Nonblocking => True Ada.Strings.Fixed.Equal_Case_Insensitive A.4.10 - Pure (from a rename) Ada.Strings.Fixed.Hash A.4.9 - Pure Ada.Strings.Fixed.Hash_Case_Insensitive A.4.9 - Pure Ada.Strings.Fixed.Less_Case_Insensitive A.4.10 - Pure Ada.Strings.Equal_Case_Insensitive A.4.10 - Pure Ada.Strings.Hash A.4.9 - Pure Ada.Strings.Hash_Case_Insensitive A.4.9 - Pure Ada.Strings.Less_Case_Insensitive A.4.10 - Pure Ada.Strings.Maps A.4.2 - Pure Ada.Strings.Maps.Constants A.4.6 - Pure Ada.Strings.Unbounded A.4.5 - Nonblocking => True Ada.Strings.Unbounded.Equal_Case_Insensitive A.4.10 - Nonblocking => True Ada.Strings.Unbounded.Hash A.4.9 - Nonblocking => True Ada.Strings.Unbounded.Hash_Case_Insensitive A.4.9 - Nonblocking => True Ada.Strings.Unbounded.Less_Case_Insensitive A.4.10 - Nonblocking => True Ada.Strings.UTF_Encoding A.4.11 - Pure Ada.Strings.UTF_Encoding.Conversions A.4.11 - Pure Ada.Strings.UTF_Encoding.Strings A.4.11 - Pure Ada.Strings.UTF_Encoding.Wide_Strings A.4.11 - Pure Ada.Strings.UTF_Encoding.Wide_Wide_Strings A.4.11 - Pure Ada.Strings.Wide_Bounded A.4.7 - Nonblocking => True Ada.Strings.Wide_Bounded.Wide_Equal_Case_Insensitive A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Bounded.Wide_Hash A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Bounded.Wide_Hash_Case_Insensitive A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Equal_Case_Insensitive A.4.7 - Pure Ada.Strings.Wide_Fixed A.4.7 - Nonblocking => True Ada.Strings.Wide_Fixed.Wide_Equal_Case_Insensitive A.4.7 - Pure (from a rename) Ada.Strings.Wide_Fixed Wide_Hash A.4.7 - Pure Ada.Strings.Wide_Fixed Wide_Hash_Case_Insensitive A.4.7 - Pure Ada.Strings.Wide_Hash A.4.7 - Pure Ada.Strings.Wide_Hash_Case_Insensitive A.4.7 - Pure Ada.Strings.Wide_Maps A.4.7 - Nonblocking => True Ada.Strings.Wide_Maps.Wide_Constants A.4.7 - Nonblocking => True Ada.Strings.Wide_Unbounded A.4.7- Nonblocking => True Ada.Strings.Wide_Unbounded.Wide_Equal_Case_Insensitive A.4.7- Nonblocking => True Ada.Strings.Wide_Unbounded.Wide_Hash A.4.7- Nonblocking => True Ada.Strings.Wide_Unbounded.Wide_Hash_Case_Insensitive A.4.7- Nonblocking => True Ada.Strings.Wide_Wide_Bounded A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Equal_Case_Insensitive A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Hash A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Hash_Case_Insensitive A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Wide_Equal_Case_Insensitive A.4.8 - Pure Ada.Strings.Wide_Wide_Fixed A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Equal_Case_Insensitive A.4.8 - Pure (from a renames) Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Hash A.4.8 - Pure Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Hash_Case_Insensitive A.4.8 - Pure Ada.Strings.Wide_Wide_Hash A.4.8 - Pure Ada.Strings.Wide_Wide_Hash_Case_Insensitive - A.4.8 - Pure Ada.Strings.Wide_Wide_Maps A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Maps.Wide_Wide_Constants A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Equal_Case_Insensitive A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Hash A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Hash_Case_Insensitive A.4.8 - Nonblocking => True Ada.Synchronous_Barriers D.10.1 - Nonblocking => True (Wait_For_Release has Nonblocking => False by D.10.1(14/3); that paragraph should be deleted). Ada.Synchronous_Task_Control D.10 - Nonblocking => True (Suspend_Until_True has Nonblocking => False by D.10(10), that sentence should be deleted). Ada.Synchronous_Task_Control.EDF D.10 - Nonblocking => False (by D.10(10.1/3), that sentence should be deleted.) Ada.Tags 3.9 - Nonblocking => True Ada.Tags.Generic_Dispatching_Constructor 3.9 - Nonblocking => Constructor'Nonblocking (* generic) Ada.Task_Attributes C.7.2 - Nonblocking => True Ada.Task_Identification C.7.1 - Nonblocking => True (Abort_Task has Nonblocking => False by C.7.1(16); that paragraph should be deleted) Ada.Task_Termination C.7.3 - Nonblocking => True Ada.Text_IO A.10.1 - Nonblocking => False (** String routines) Ada.Text_IO.Bounded_IO A.10.11 - Nonblocking => False -- I/O Ada.Text_IO.Complex_IO G.1.3 - Nonblocking => False -- I/O Ada.Text_IO.Editing F.3.3 - Nonblocking => False (** String routines) Ada.Text_IO.Text_Streams A.12.2 - Nonblocking => False Ada.Text_IO.Unbounded_IO A.10.12 - Nonblocking => False Ada.Unchecked_Conversion 13.9 - Nonblocking => True (Pure but generic) Ada.Unchecked_Deallocate_Subpool 13.11.5 - Nonblocking => False (*** user calls) Ada.Unchecked_Deallocation 13.11.2 - Nonblocking => True Ada.Wide_Characters A.3.1 - Pure Ada.Wide_Characters.Handling A.3.5 - Pure Ada.Wide_Text_IO A.11 - Nonblocking => False (** String routines) Ada.Wide_Text_IO.Complex_IO G.1.4 - Nonblocking => False -- I/O Ada.Wide_Text_IO.Editing F.3.4 - Nonblocking => False (** String routines) Ada.Wide_Text_IO.Text_Streams A.12.3 - Nonblocking => False Ada.Wide_Text_IO.Wide_Bounded_IO A.11 - Nonblocking => False -- I/O Ada.Wide_Text_IO.Wide_Unbounded_IO A.11 - Nonblocking => False Ada.Wide_Wide_Characters A.3.1 - Pure Ada.Wide_Wide_Characters.Handling A.3.6 - Pure Ada.Wide_Wide_Text_IO A.11 - Nonblocking => False (** String routines) Ada.Wide_Wide_Text_IO.Complex_IO G.1.4 - Nonblocking => False -- I/O Ada.Wide_Wide_Text_IO.Editing F.3.4 - Nonblocking => False (** String routines) Ada.Wide_Wide_Text_IO.Text_Streams A.12.3 - Nonblocking => False Ada.Wide_Wide_Text_IO.Wide_Wide_Bounded_IO A.11 - Nonblocking => False -- I/O Ada.Wide_Wide_Text_IO.Wide_Wide_Unbounded_IO A.11 - Nonblocking => False Interfaces B.2 - Pure Interfaces.C B.3 - Pure Interfaces.C.Pointers B.3.2 - Nonblocking => True Interfaces.C.Strings B.3.1 - Nonblocking => True Interfaces.COBOL B.4 - Nonblocking => True Interfaces.Fortran B.5 - Pure System 13.7 - Pure System.Address_To_Access_Conversions 13.7.2 - Nonblocking => True System.Machine_Code 13.8 - (**** Impl def) System.Multiprocessors D.16 - Nonblocking => True System.Multiprocessors.Dispatching_Domains D.16.1 - Nonblocking => True System.RPC E.5 - Nonblocking => False (E.5(23) says this explicitly; that paragraph should be deleted.) System.Storage_Elements 13.7.1 - Pure System.Storage_Pools 13.11 - Nonblocking => False (*** user overriding) System.Storage_Pools.Subpools 13.11.4 - Nonblocking => False (*** user overriding) Items marked "Pure" are pure, and thus automatically are Nonblocking. Items marked "(* generic)" have Nonblocking given as a formula. This automatically matches the nonblocking setting to that of the actual parameters (see the !discussion for more on this). The containers will be like this as well. Items marked "(** String routines)" have Get/Put routines that operate only on Strings -- those explicitly have Nonblocking => True specified. That's in accordance with the AARM note 9.5.1(18.a) (and an old AI). Items marked "(*** user overriding)" are mainly used to provide a framework for user code (as in storage pools or streams). Since all dispatching calls have to "assume the worst" for nonblocking, and we have to keep compatibility with existing Ada code, we cannot make such packages (and types) nonblocking. The user can explicitly mark their overriding routines Nonblocking (overridings of "allows blocking" subprograms can be declared nonblocking, but the other way around is prohibited). Items marked "(*** user calls)" make calls on code that is potentially user-defined via dispatching. These usually work in conjunction with types declared in packages associated with the previous item. Items marked "(**** impl def)" have implementation-defined contents, so we need say nothing. Items marked "(**** AB)" were verified with Alan Burns. Since explicit wording is needed in Ada 2012 to specify that a routine is potentially blocking, the lack of such wording could mean either that the subprogram was considered and should be nonblocking, or that no one considered whether the subprogram needs to be potentially blocking. As such, I verified with Alan Burns whether any packages that have no evidence that nonblocking was considered need to be explicitly potentially blocking (see e-mail of January 11, 2017, and the reply). In particular, Ada.Dispatching.EDF.Delay_Until_and_Set_Deadline, which includes the semantics of a delay statement, needs to be potentially blocking but isn't declared this way in the RM. End lengthy editor's note.] !discussion We considered changing the aspect name from "Nonblocking" to "Potentially_Blocking," as that matches RM terminology better, but we ultimately concluded that would be a mistake. Furthermore, "nonblocking" is used in 9.5.1, albeit somewhat informally. Were we to switch to Potentially_Blocking, the default would be True rather than False, which is unlike other Boolean aspects. Furthermore, with Potentially_Blocking => True, we wouldn't *require* that it be potentially blocking, merely allow it. Perhaps Allow_Blocking would be better, but that doesn't match RM terminology at all, and still has the "wrong" default. We initially modeled this aspect after No_Return, which has a somewhat similar purpose and presumably has already worked out some of the needed rules. However, we have gone beyond that, because we now have nonblocking access-to-subprogram types, nonblocking formal subprograms, etc. The aspect is described as being a boolean valued expression, but our intent is that it act like a boolean-valued aspect outside of any generic unit. Thus it is required to be static in such contexts, the expression can be omitted when it is specified (in which case it represents the expression of the boolean literal True), it can only be changed to True for derived types, and so on. We repeat these rules even when the 13.1.1 blanket rules can be read to apply, as that might be surprising to a reader. The rules do not allow calling "normal" subprograms from a nonblocking subprogram. This allows detecting any potentially blocking operations used in a nonblocking subprogram statically. This is important if pragma Detect_Blocking is used, as such detection is required. (Otherwise, this is just a bounded error and the "mistake" can be ignored with the usual consequences.) We have provided package-level defaults, given that many packages will have all of their subprograms non-blocking. We chose to make the default for a declared pure, non-generic library unit to be nonblocking, as that is almost always the case, since blocking typically implies the use of some kind of global lock. We do not foresee significant incompatibilities, since declared pure library units may only depend on other declared pure library units. For pure generic units we leave the default at False for compatibility reasons, because these might have existing instances where an actual subprogram (or access-to-subprogram type) is potentially blocking. We did not specify that protected subprograms are by default Nonblocking=>True, since that would be incompatible, as they then could not call subprograms with a default Nonblocking aspect value of False. It might be possible to specify Nonblocking=>True as the default for protected subprograms in a future version of the standard (and clearly an implementation could at least provide a warning when a call is made to a subprogram with Nonblocking of False). Because of the confusion related to the fact that protected operations are always required to be nonblocking at run-time, we don't allow specifying the attribute directly on an individual protected operation. However, we allow specifying Nonblocking on a protected unit to determine the setting for all of the enclosed protected operations. This allows rejection of protected operations that call or use allows blocking operations. We only allow specifying a conforming expression (essentially a confirming value) of Nonblocking on a generic instantiation; the value of the aspect comes from the generic unit (possibly after re-evaluating the aspect based on the values of the actual parameters). Specifying a different value would simply be confusing, as it wouldn't change the enforcement of Legality Rules in the generic unit (and it would be wrong to supply a value of True for an instance of a unit that has the value of False, as in that case no rules would have been enforced in the body). ---- The attribute Nonblocking is primarily useful for use in the Nonblocking aspect of other subprograms, and mainly for the non-blocking property of formal subprograms and other formal parameters. We allow the prefix to be any subprogram to avoid having special cases, and as it may be useful to ensure that a group of subprograms all have the same contract. In the case of nonblocking, that could be accomplished with a constant, but in the case of other static contracts that we are considering like exception contracts (AI12-0015-1) and global contracts (AI12-0079-1), a mechanism to copy them will be valuable (especially as they may be lengthy). As we want all of the contracts to work as similarly as possible, we make the attribute Nonblocking as general as possible. The primary use for this attribute is in aspects of generic units. The attribute makes it possible for a generic unit to have a nonblocking aspect that depends on those of the actual subprograms. That's especially important for the containers, which we want to be primarily nonblocking. This mechanism takes some effort for the implementer of a generic unit, but it means that the instantiator of such a unit does not need to worry about nonblocking, as the most restrictive setting compatible with the actual subprograms will automatically be chosen. Unfortunately, this mechanism doesn't have an obvious extension to support anonymous access-to-subprogram parameters; the type is anonymous and the actual is typically an Access attribute. One could imagine allowing the prefix to be a parameter, something like: procedure Iterate (Container : in Hashed_Maps; Process : not null access procedure (Position : in Cursor) when Nonblocking => Process'Nonblocking and Hash'Nonblocking and Equivalent_Keys'Nonblocking); But in that case the Nonblocking value would have to be determined based on the actuals of the call; it would be weird for the Legality of a call to depend on the details of actual parameters. Thus we didn't propose such a mechanism. ---- We could simplify this proposal further by dropping the ability to specify Nonblocking on generic formal parameters, and just depending on the Nonblocking attribute to handle that. That would eliminate the rules about generic formal matching. We didn't do that as that would require having nonblocking attributes for formal objects (which would reduce the value somewhat), and would eliminate the "easy" solution for new code (which is to simply require everything to be nonblocking). Not everyone needs to write the most flexible possible generics. --- The assume-the-worst rules are fairly complex, in that we want to allow the intended cases without accidentally allowing illegal situations in instances. Just assuming that the aspects have the value True works for the intended usage, but we have to detect errors in that usage. For instance, consider the following example: generic type P is private; Obj : P; function F (Param : P) return Boolean; package Gen is with Nonblocking => P'Nonblocking and F'Nonblocking; procedure Proc (Param : P); end Gen; package body Gen is procedure Proc (Param : P) is begin if P = Obj then -- (1) ... elsif F (P) then -- (2) ... end if; end Proc; end Gen; In this normal usage, the entire generic has a nonblocking aspect based on the "and" of the actuals Nonblocking status. This means that procedure Proc also inherits this aspect. As such, (1) and (2) should be allowed, as any legal instance will work. A "split" instance (where the Nonblocking aspects differ; for instance when P is nonblocking and F allows blocking) will end up allowing blocking for Proc. We avoid any check as the assume-the-worst says no check is needed for a call whose Nonblocking aspect exactly matches some portion of the aspect expression combined with "and" for the subprogram as a whole. One can also imagine a belt-and-suspenders approach where *everything* is specified: generic type P is private with Nonblocking => P'Nonblocking; Obj : P; function F (Param : P) return Boolean with Nonblocking => F'Nonblocking; package Gen is with Nonblocking => P'Nonblocking and F'Nonblocking; procedure Proc (Param : P); end Gen; This also works fine (assuming the same body), as the same matching rule applies. In this case, Proc will only be nonblocking if both P and F are nonblocking, so there can be no problem with the calls to either. Similarly, if we wanted to specify a more limited nonblocking for a different procedure, we could do that: generic type P is private; Obj : P; function F (Param : P) return Boolean; package Gen2 is with Nonblocking => P'Nonblocking and F'Nonblocking; procedure Proc2 (Param : P) with F'Nonblocking; end Gen2; package body Gen2 is procedure Proc2 (Param : P) is begin if F (P) then -- (3) ... end if; end Proc; end Gen2; In this case, the aspect of the subprogram called at (3) (that of the actual, F'Nonblocking) exactly matches that of the checked subprogram (Proc2). This is true even if the actual for P allows blocking, since no allows blocking operation of P is called in Proc2. As noted before, we need the complex rules in order to avoid problems when someone screws up. Consider a version of the Gen2 that puts the wrong aspect on Proc2: generic type P is private; Obj : P; function F (Param : P) return Boolean; package Gen2 is with Nonblocking => P'Nonblocking and F'Nonblocking; procedure Proc2 (Param : P) with P'Nonblocking; end Gen2; Again, any combination of nonblocking aspects of the actuals would be legal. The rules as described make the call at (3) illegal (as the aspects don't conform). This is important, as the case where the actual for F allows blocking and the actual for P is nonblocking would lead to a nonblocking subprogram calling a subprogram that allows blocking. However, our initial rule of treating all of the attributes as having the value True would have allowed this case (since both Proc2 and F have values that derive from formal entities, just different ones). That can't be allowed. Similarly, consider mistakenly using "or" instead of "and" for the unit in the general case: generic type P is private; Obj : P; function F (Param : P) return Boolean; package Gen is with Nonblocking => P'Nonblocking or F'Nonblocking; procedure Proc (Param : P); end Gen; This wouldn't change the legality of the actuals at all. The rules as described would make both calls (1) and (2) illegal, as the neither of the aspects of the formal would conform with the aspect inherited for Proc (and the "and" rule for portions would not apply). Again, in the case where the actual for F allows blocking and the actual for P is nonblocking we would have a nonblocking subprogram Proc calling a subprogram F (2) that allows blocking, so this indeed has to be illegal. (The call (1) would not be a problem in that case, but reverse the blocking of the actuals and then (1) would be the problematic call.) Again, the initial rule would not have detected the problem. --- Comparing Alternative 1 with this proposal. The problem with alternative 1 is that a generic unit like the containers can be set to nonblocking, but then using this with an allows blocking routine requires an explicit override by the user on the instance. Since the default for most routines is that they are not nonblocking, this could provide a significant compatibility problem. An alternative for alternative 1 would be to declare units like the containers to be allows blocking; but then they can never be nonblocking (and we surely want to use them as nonblocking). In contrast, this proposal puts all of the burden on the implementer of a package (where it should be) and none on the user of the package. Alternative 1 is definitely easier for the implementer of a package, and harder for a user. Container usage examples: Imagine that a user has an existing user-defined Hash function: subtype Label is String (1..10); function Hash (Key : in Label) return Ada.Containers.Hash_Type; With this proposal (as outlined in the example section below), if they don't care about nonblocking (as is likely to be the case for recompiling existing code), their existing instantiation will compile with no problem: package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "="); If they do care about blocking behavior, they can add Nonblocking to Hash and they will get the Nonblocking behavior they want: function Hash (Key : in Label) return Ada.Containers.Hash_Type with Nonblocking => True; Alternatively, they could declare the instance to be Nonblocking: package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "=") with Nonblocking => True; which would cause an error (as Nonblocking is False), hopefully with an error message that Hash has Nonblocking set as False (since that's the default). With a good error message, the correct fix should be easy to find. ------------------- For alternative 1 (as described in AI12-0064-1/05), the situation is different. The original instantiation of: package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "="); is now illegal, as Hash has Nonblocking = False, and that fails to match the default for the formal parameter Hash (which is Nonblocking => True). Thus the user has to change their code and add Nonblocking => True to Hash or add Nonblocking => False to the instance My_Hashed_Map. That doesn't seem good. If the default of Ada.Containers.Hashed_Map is changed to False, then the above works, but then there no longer is any way to get a Nonblocking container. package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "=") with Nonblocking => True; should be illegal in this case, as the restrictions were not enforced in the generic body. --------------- There is one known problem with this proposal as it is written. The prefix of the Nonblocking attribute has to resolve without any context. That means that in many circumstances, overloaded prefixes aren't going to be usable. That could be a problem for operators (like "=" in the containers) that are widely used. I considered using subprogram calls rather than subprogram names in the prefix, but that ran into issues both with having appropriate parameters to use (in the generic case) and with evaluation of the prefix (which we don't want to do). I also considered using qualification, but that doesn't help for relational operators (they all return Boolean!). It's possible to rename operators to unique names, so the problem isn't unsurmountable, but of course that clutters the name space of packages. (We can use renames as aspects aren't resolved until the freezing point.) One of course can avoid using operators in generic specifications, but that's impractical for existing generics and a usage pain for new generics. !example package Ada.Text_IO with Nonblocking => False is ... generic type Enum is (<>); package Enumeration_IO is -- implicitly Nonblocking => False Default_Width : Field := 0; Default_Setting : Type_Set := Upper_Case; procedure Get(File : in File_Type; -- implicitly Nonblocking => False ... procedure Get(From : in String; Item : out Enum; Last : out Positive) with Nonblocking => True; -- explicitly Nonblocking => True procedure Put(To : out String; Item : in Enum; Set : in Type_Set := Default_Setting) with Nonblocking => True; -- explicitly Nonblocking => True end Enumeration_IO ... end Ada.Text_IO; with Ada.Iterator_Interfaces; generic type Key_Type is private; type Element_Type is private; with function Hash (Key : Key_Type) return Hash_Type; with function Equivalent_Keys (Left, Right : Key_Type) return Boolean; with function "=" (Left, Right : Element_Type) return Boolean is <>; package Ada.Containers.Hashed_Maps is with Nonblocking => Key_Type'Nonblocking and Element_Type'Nonblocking and Hash'Nonblocking and Equivalent_Keys'Nonblocking and Element_Equal'Nonblocking; pragma Preelaborate(Hashed_Maps); pragma Remote_Types(Hashed_Maps); function Element_Equal (Left, Right : Element_Type) return Boolean renames "="; -- Rename of formal "=". ... procedure Iterate (Container : in Map; Process : not null access procedure (Position : in Cursor)) with Nonblocking => False; ... end Ada.Containers.Hashed_Maps; Alternatively, we could separately specify the blocking for the individual routines, depending on which of the formal routines they are allowed to use. (Given that we leave that unspecified in the Standard, it's probably better to use a global setting as was done here.) !corrigendum 3.10.2(32/3) @drepl @xindent
), as determined by the expected type. The accessibility
level of P shall not be statically deeper than that of @i. In
addition to the places where Legality Rules normally apply (see
12.3), this rule applies also in the private part of an instance
of a generic unit. The profile of P shall be subtype conformant
with the designated profile of @i, and shall not be Intrinsic.
If the subprogram denoted by P is declared within a generic unit,
and the expression P'Access occurs within the body of that generic
unit or within the body of a generic unit declared within
the declarative region of the generic unit, then the ultimate ancestor
of @i shall be either a nonformal type declared within the generic
unit or an anonymous access type of an access parameter.>
@dby
@xindent
), as determined by the expected type. The accessibility
level of P shall not be statically deeper than that of @i
Denotes whether package P is considered nonblocking; the type
of this attribute is the predefined type Boolean.
P'Nonblocking represents the nonblocking expression of P;
evaluation of P'Nonblocking evaluates that expression.>
For a @fa declared inside of a generic unit but not in a generic body
or that is a generic specification not declared in a generic unit
is considered nonblocking for the purposes of checking the restrictions on a
nonblocking unit only if the value of its Nonblocking aspect is statically
True. For the purposes of checks in @i , a call to a subprogram is considered
nonblocking unless the value of its Nonblocking aspect is statically False.
A program unit @i declared inside of a generic body or that is a generic body
is considered nonblocking for the purposes of checking the restrictions on a
nonblocking unit unless the value of its Nonblocking aspect is statically
False. For the purposes of checks in @i , a call to a subprogram is considered
to allow blocking unless:
@xbullet that is combined with the remainder of the
nonblocking expression of @i by one or more @b.
If @i is nonblocking, P shall be nonblocking. In
addition to the places where Legality Rules normally apply (see
12.3), these rules apply also in the private part of an instance
of a generic unit. The profile of P shall be subtype conformant
with the designated profile of @i, and shall not be Intrinsic.
If the subprogram denoted by P is declared within a generic unit,
and the expression P'Access occurs within the body of that generic
unit or within the body of a generic unit declared within
the declarative region of the generic unit, then the ultimate ancestor
of @i shall be either a nonformal type declared within the generic
unit or an anonymous access type of an access parameter.>
!corrigendum 4.6(24.21/4)
@dinsa
@xinbull
Denotes whether subprogram S is considered nonblocking; the type
of this attribute is the predefined type Boolean.>
@xindent
For a @fa
Denotes whether predefined operators (and in the case of
access-to-subprogram subtypes) a subprogram designated by a value of
type S are considered nonblocking; the type of this attribute is the
predefined type Boolean. S'Nonblocking represents the nonblocking
expression of S; evaluation of S'Nonblocking evaluates that expression.>
The following are defined to be @i