!standard 3.3(23/3) 18-12-10 AI12-0294-1/04 !standard 5.5(8) !standard 5.5(9/5) !standard 5.5(9.1/5) !standard 5.5.3(20/5) !standard 9.10.1(8/5) !standard D.2.1(1.5/2) !class Amendment 18-11-15 !status Amendment 1-2012 18-11-15 !status WG9 Approved 22-06-22 !status ARG Approved 8-0-3 18-10-21 !status work item 18-11-15 !status received 18-10-21 !priority Low !difficulty Easy !subject More clean-ups for Ada 2020 !summary [Editor's note: These cleanups have already been applied to the draft Standard.] Various minor issues are corrected: (1) Accept statements are banned in the body of a procedural iterator loop. (2) Wording involving the nominal subtype of an object is improved. (3) The elaboration order of a chunk_specification and a loop_parameter_specification is that the chunk_specification is elaborated first. (4) There is an assume-the-worst rule for aspect Yield used on subprograms declared inside a generic body. (5) Wording describing the default conflict checking policy is added. !problem Various minor issues, mostly caused by other Amendment AIs, are repaired. (1) 5.5.3 (from AI12-0189-1) allows accept statements in the body of a procedural iterator loop. However, such accept statements would be illegal if the loop was written manually (as 9.5.2(14) would be violated. (2) 3.3(23/3) contains the following sentence: "The object's actual subtype (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is if the nominal subtype is an indefinite subtype." The middle "is" in this sentence is hanging and it's unclear to what it refers. This should be clarified. (3) AI12-0251-1 proposes that a loop_parameter_specification is elaborated and parameters are created before the chunk_specification, if any, is elaborated. But the number of loop parameters to create is determined, in part, by the chunk_specification. Moreover, this is specifying an order different than the order in which these constructs are written. This is weird. (4) AI12-0279-1 adds a rule to prevent Nonblocking => True and Yield => True from being given for the same subprogram (since Yield requires blocking, it is incompatible with Nonblocking). However, Legality Rules are not enforced in instance bodies, and the rule is written to exclude most uses of Nonblocking in generic units from the check. Therefore, an assume-the-worst rule is needed in generic bodies to prevent the impossible case from happening. (5) One of the new Legality Rules added by AI12-0267-1 [9.10.1(8/5)] reads: If multiple Conflict_Check_Policy pragmas apply to a given construct, the conflict check policy is determined by the one in the innermost enclosing region. If no such Conflict_Check_Policy pragma exists, the policy is Parallel_Conflict_Checks (see below). The second sentence here appears to modify the first, but that is not the intent. !proposal (See Summary.) !wording (1) Add after 5.5.3(20/5) [from AI12-0189-1]: The sequence_of_statements of a loop_statement with a procedural_iterator as its iteration_scheme shall not contain an accept_statement whose entry_declaration occurs outside the loop_statement. AARM Reason: An accept_statement is not allowed in a procedure (see 9.5.2), it has to be directly in a task_body. Since the loop body here is implemented as a procedure, we can't allow accept_statements there, either, even if the loop itself is directly in a task_body. AARM Ramification: This includes cases where the accept_statement is part of another construct, for instance, a select_statement. (2) Modify 3.3(23/3): The object's actual subtype (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is {more restrictive} if the nominal subtype is an indefinite subtype. (3) Replace 5.5(9/5-9.1/5): [As modified by AI12-0119-1 and AI12-0251-1] If the reserved word parallel is present in a loop_statement (a /parallel loop/), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9). If a chunk_specification is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the chunk_specification is an /integer_/simple_expression, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a discrete_subtype_definition is present, the elaboration elaborates the discrete_subtype_definition, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the chunk_specification, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised. For the execution of a loop_statement that has an iteration_scheme including a loop_parameter_specification, after elaborating the chunk_specification, if any, the loop_parameter_specification is elaborated. This elaboration elaborates the discrete_subtype_definition, which defines the subtype of the loop parameter. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a /sequential loop/), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. AARM To Be Honest: This wording does not describe when the loop parameter object(s) are created. That creation has no side-effects (other than possibly raising Storage_Error, but anything can do that), so we simplified the wording by leaving it out. Each object has to be created before any iteration that depends on it starts, but we do not (for instance) require that the objects are all created at once at the start of the loop, nor that the objects are created after the elaboration of the discrete_subtype_definition. If a chunk_specification with a discrete_subtype_definition is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters. Delete AARM 5.5(9.a) (it is effectively replaced by the AARM note given above) (4) Replace D.2.1(9/5) [as added by AI12-0279-1] with: If a Yield aspect is specified True for a primitive subprogram S of a type T, then the aspect is inherited by the corresponding primitive subprogram of each descendant of T. Legality Rules If the Yield aspect is specified for a dispatching subprogram that inherits the aspect, the specified value shall be confirming. If the Nonblocking aspect (see 9.5) of the associated callable entity is statically True, the Yield aspect shall not be specified as True. For a callable entity that is declared within a generic body, this rule is checked assuming that any nonstatic Nonblocking attributes in the expression of the Nonblocking aspect of the entity are statically True. AARM Reason: The second sentence here is an assume-the-worst rule. The only Nonblocking attributes that are nonstatic are those that depend, directly or indirectly, on the nonblocking aspect of a generic formal parameter. We have to assume these might in fact have the value True if given an appropriate actual entity. In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit. (5) Replace the second sentence of 9.10.1(8/5) with: If no Conflict_Check_Policy pragma applies to a construct, the policy is Parallel_Conflict_Checks (see below). AARM To Be Honest: The region mentioned in this rule is the region to which the policy pragma applies, and not the declarative region in which the policy pragma appears. This distinction matters when there are multiple policy pragmas in a single declarative region. !discussion (1) As noted in the problem, 9.5.2(14) would make an accept statement illegal in a procedure, if the loop was written explicitly. Of course, that's true for exit and goto as well, and we require those to be implemented. But those terminate the iteration, while an accept statement would not have that effect. So supporting that would complicate the implementation for no obvious benefit. Therefore, we ban then unconditionally in this case. (2) This wording goes back to the 2.0 version of Ada 9x (that is, the first version with actual wording), so fixing it isn't a priority. However, the original question arose from an ARG member who though that "as" was missing from this text. The resulting sentence would violate the Dewar rule (surely not all nominal subtypes are indefinite). The author then spent a substantial amount of time trying to figure out a meaning that doesn't violate the Dewar rule. A normal reader shouldn't have to apply the Dewar rule to be able to read the RM, thus we clarify the sentence. No change in meaning is intended. (3) It appears that it was easier to fit chunk_specifications into the existing wording if they were elaborated later. But, as noted above, that causes ramifications that are problematical. While the creation of loop parameters doesn't have any detectable effect, it still seems strange to require doing something before there is enough information to decide the details of what to do. In reversing the elaboration, we also reversed the order of the paragraphs in the wording. This required substantial revisions to the wording, so that the definitions of "parallel loop" and "chunk" come before the usages. (4) Since the Yield implies that a potentially blocking call will be part of the subprogram body, it is by definition incompatible with Nonblocking => True. We can't allow this problem to go undetected, as it could cause blocking to happen inside of a parallel construct or protected actions, neither of which may be prepared for blocking. Consider the following generic: generic type Priv is private; with procedure Munge (Obj : in out Priv); package Gen is procedure Proc1 (Obj : in out Priv) with Nonblocking => Munge'Nonblocking, Yield => True; private procedure Proc2 (Obj : in out Priv) with Nonblocking => Munge'Nonblocking, Yield => True; end Gen; package body Gen is procedure Proc3 (Obj : in out Priv) with Nonblocking => Munge'Nonblocking, Yield => True; end Gen; All of these are legal in the generic, as Munge'Nonblocking is not "statically true". If Gen is instantiated with a procedure that is Nonblocking, then all three of Proc1, Proc2, and Proc3 will be nonblocking in the instance. Proc1 will be rechecked by the normal legality rule processing, thus making the instance illegal. Proc2 will be rechecked because we added the usual boilerplate about checking in the private part. However, Proc3 will never be rechecked, and thus a dangerous subprogram could be declared and used. The only way to prevent this problem is to reject Proc3 assuming that some instance will have Munge'Nonblocking evaluate to True. This should not present a problem in practice, since if a declaration like Proc3 is required, it can always be moved to the private part (like Proc2), where it will be legal and be rechecked as needed. A second workaround would be to give the declaration of Munge the aspect Nonblocking => False, so that the contract is visible. (5) We clarify the wording to make it clear that we are talking about all cases where there is no pragma that applies. Then the paragraph describes all of the cases other than the obvious one where exactly one pragma applies. The intent of these rules is that the scoping works similarly to that of checking pragmas (Suppress/Unsuppress). So "region" is the region of application of the pragma, and not the declarative region in which the pragma appears. We add a To Be Honest note to clarify in case anyone would imagine something else. !corrigendum 3.3(23/3) @drepl At the place where a view of an object is defined, a @i is associated with the view. The object's @i (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is if the nominal subtype is an @i. A subtype is an indefinite subtype if it is an unconstrained array subtype, or if it has unknown discriminants or unconstrained discriminants without defaults (see 3.7); otherwise, the subtype is a @i subtype (all elementary subtypes are definite subtypes). A class-wide subtype is defined to have unknown discriminants, and is therefore an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional @fa or explicit initialization @fa is necessary (see 3.3.1). A component cannot have an indefinite nominal subtype. @dby At the place where a view of an object is defined, a @i is associated with the view. The object's @i (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is more restrictive if the nominal subtype is an @i. A subtype is an indefinite subtype if it is an unconstrained array subtype, or if it has unknown discriminants or unconstrained discriminants without defaults (see 3.7); otherwise, the subtype is a @i subtype (all elementary subtypes are definite subtypes). A class-wide subtype is defined to have unknown discriminants, and is therefore an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional @fa or explicit initialization @fa is necessary (see 3.3.1). A component cannot have an indefinite nominal subtype. !corrigendum 5.5(8) @dinsa For the execution of a @fa with a @b @fa, the @fa is evaluated before each execution of the @fa; if the value of the @fa is True, the @fa is executed; if False, the execution of the @fa is complete. @dinst If the reserved word @b is present in the @fa of a @fa (a @i), the iterations are partitioned into one or more @i, each with its own separate logical thread of control (see clause 9). If a @fa is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the @fa is an @i@fa, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a @fa is present, the elaboration elaborates the @fa, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the @fa, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised. !corrigendum 5.5(9/4) @drepl For the execution of a @fa with the @fa being @b @fa, the @fa is first elaborated. This elaboration creates the loop parameter and elaborates the @fa. If the @fa defines a subtype with a null range, the execution of the @fa is complete. Otherwise, the @fa is executed once for each value of the discrete subtype defined by the @fa that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter. These values are assigned in increasing order unless the reserved word @b is present, in which case the values are assigned in decreasing order. @dby For the execution of a @fa that has an @fa including a @fa, after elaborating the @fa, if any, the @fa is elaborated. This elaboration elaborates the @fa, which defines the subtype of the loop parameter. If the @fa defines a subtype with a null range, the execution of the @fa is complete. Otherwise, the @fa is executed once for each value of the discrete subtype defined by the @fa that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a @i), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word @b is present, in which case the values are assigned in decreasing order. If a @fa with a @fa is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the @fa. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters. Whether or not a @fa is present in a parallel loop, the total number of iterations of the loop represents an upper bound on the number of logical threads of control devoted to the loop. !comment The following is mainly to force a conflict. !corrigendum 5.5.3(0) @dinsa The @fa of a @fa with a @fa as its @fa shall contain an @fa, return statement, @fa, or @fa that leaves the loop only if the callable entity @i associated with the @fa has an Allows_Exit aspect specified True. @dinst The @fa of a @fa with a @fa as its @fa shall not contain an @fa whose @fa occurs outside the @fa. !comment The following is mainly to force a conflict. !corrigendum 9.10.1(0) @drepl If multiple Conflict_Check_Policy pragmas apply to a given construct, the conflict check policy is determined by the one in the innermost enclosing region. If no such Conflict_Check_Policy pragma exists, the policy is Parallel_Conflict_Checks (see below). @dby If multiple Conflict_Check_Policy pragmas apply to a given construct, the conflict check policy is determined by the one in the innermost enclosing region. If no Conflict_Check_Policy pragma applies to a construct, the policy is Parallel_Conflict_Checks (see below). !corrigendum D.2.1(1.5/2) @dinsa Dispatching serves as the parent of other language-defined library units concerned with task dispatching. @dinss For a noninstance subprogram (including a generic formal subprogram), a generic subprogram, or an entry, the following language-defined aspect may be specified with an @fa (see 13.1.1): @xhang<@xterm The type of aspect Yield is Boolean.> @xindent shall be a static expression. If not specified (including by inheritance), the aspect is False.> @xindent of a type @i, then the aspect is inherited by the corresponding primitive subprogram of each descendant of @i.> @s8<@i> If the Yield aspect is specified for a dispatching subprogram that inherits the aspect, the specified value shall be confirming. If the Nonblocking aspect (see 9.5) of the associated callable entity is statically True, the Yield aspect shall not be specified as True. For a callable entity that is declared within a generic body, this rule is checked assuming that any nonstatic Nonblocking attributes in the expression of the Nonblocking aspect of the entity are statically True. In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit. !ASIS No changes needed. !ACATS test An ACATS B-Test is needed for (1). No test is needed for (2). !appendix From: Randy Brukardt Sent: Friday, November 16, 2018 7:16 PM AI12-0251-1 defines the chunk syntax as: parallel [(chunk_specification)] for loop_parameter_specification but the Dynamic Semantics are: The chunk_specification is elaborated after the loop_parameter_specification is elaborated, and before any iterations are performed. Why is the elaboration in the opposite order of the textual appearance? I can't think of any reason that elaboration of one should have anything to do with elaboration of the other, so this order seems arbitrary. In such a case, I'd expect the order to be textual (that's certainly the order that a reader would expect). Moreover, you can't actually do anything until both are elaborated (you have to know how many chunks there are before you can do any iterations), so I don't see any implementation reason for this choice. The only reason that I can see for this choice is that it caused less change in the wording, but that shouldn't be the reason for any choice which has a run-time consequence. Is there something that I missed? I'd either leave the order unspecified (but that would be unusual for elaboration) or do the elaboration in textual order. I can't think of any other case where elaboration is done out-of-order within a single construct. *************************************************************** From: Randy Brukardt Sent: Friday, November 16, 2018 7:59 PM ... > Why is the elaboration in the opposite order of the textual > appearance? Note that arguably this order is outright wrong, since the existing wording says: For the execution of a loop_statement with the iteration_scheme including a loop_parameter_specification, the loop_parameter_specification is first elaborated. This elaboration creates the loop parameter and elaborates the discrete_subtype_definition. But how can you create "the loop parameter" when you don't know how many chunks there are? Since this creation doesn't have any actual effect, it's probably safe to ignore that wording, but still it doesn't make a ton of sense. **************************************************************** From: Tucker Taft Sent: Friday, November 16, 2018 9:22 PM I agree it makes more sense to elaborate in the textual order. **************************************************************** From: Randy Brukardt Sent: Wednesday, November 21, 2018 7:45 PM I'm trying to word this for the cleanup AI. The simple fix is just to reword the existing paragraphs as needed: Modify 5.5(9/5): [As modified by AI12-0119-1 and AI12-0251-1] For the execution of a loop_statement with the iteration_scheme including a loop_parameter_specification, the loop_parameter_specification is [first] elaborated{ after any chunk_specification (see below)}. This elaboration creates the loop parameter and elaborates the discrete_subtype_definition. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter. If the reserved word parallel is present (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9), and its own copy of the loop parameter; otherwise a single logical thread of control performs the loop. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. Modify 5.5(9.1/5): [As modified by AI12-0251-1] If a chunk_specification is present in a parallel loop, it determines the maximum number of logical threads of control devoted to the parallel loop. The chunk_specification is elaborated {before}[after] the loop_parameter_specification is elaborated[, and before any iterations are performed]. If the chunk_specification is an /integer_/simple_expression, this elaboration evaluates the expression, and the value of the expression determines the maximum number of logical threads of control devoted to the parallel loop. If a discrete_subtype_definition is present, this elaboration elaborates the discrete_subtype_definition, and creates one or more logical threads of control, each having its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. If there is a chunk parameter, its assigned value increases with increasing values of the loop parameter. When the chunk_specification is elaborated, a check is made that the determined maximum number of logical threads of control is greater than zero. If this check fails, Program_Error is raised. ============ But this order is weird, because the second item elaborated comes first. Just reversing the paragraphs doesn't work, because the first paragraph has the definitions of "parallel loop" and "chunk" that are used in the second paragraph. So we'd have to rewrite this extensively to make that work, possibly something like: [The change information doesn't reflect the change in the order of the paragraphs.] {If the reserved word parallel is present in a loop_statement (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9).} If a chunk_specification is present in a parallel loop, it determines the maximum number of logical threads of control devoted to the parallel loop. The chunk_specification is {first} elaborated [after the loop_parameter_specification is elaborated, and before any iterations are performed]. If the chunk_specification is an /integer_/simple_expression, this elaboration evaluates the expression, and the value of the expression determines the maximum number of logical threads of control devoted to the parallel loop. If a discrete_subtype_definition is present, this elaboration elaborates the discrete_subtype_definition, and creates one or more logical threads of control, each having its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. If there is a chunk parameter, its assigned value increases with increasing values of the loop parameter. When the chunk_specification is elaborated, a check is made that the determined maximum number of logical threads of control is greater than zero. If this check fails, Program_Error is raised. For the execution of a loop_statement with the iteration_scheme including a loop_parameter_specification, the loop_parameter_specification is [first] elaborated{ after any chunk_specification}. This elaboration creates the loop parameter and elaborates the discrete_subtype_definition. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter. {For a parallel loop, each chunk has}[If the reserved word parallel is present (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with] its own separate logical thread of control [(see clause 9)], and its own copy of the loop parameter; {for other loops,}[otherwise] a single logical thread of control performs the loop. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. ----------- Is this enough better to use instead of the previous version? Or is this not worth the redo? There's a bit of duplication about the logical threads of control, but I thought we needed the reason for the chunks to appear up front. Any suggestions or improvements??? **************************************************************** From: Tucker Taft Sent: Wednesday, November 21, 2018 8:53 PM Let me give it a try. I think your second version is an improvement, but it still seems a bit weird to start talking about creating multiple loop parameters before we even elaborate the definition of the loop parameter. I'll send a reply at some point over the long weekend. **************************************************************** From: Randy Brukardt Sent: Wednesday, November 21, 2018 9:12 PM Sounds good. I probably won't look at it until Monday anyway (leaving for the holiday soon). Keep in mind that there is a small third paragraph that I didn't show (or change) in the version I sent. You might want to stick it into the blender as well as the parts I showed. *************************************************************** From: Tucker Taft Sent: Wednesday, November 21, 2018 9:39 PM Below is an attempt. I am not going to use "{}" or "[]" because I think it just adds to the confusion. If the reserved word parallel is present in a loop_statement (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9). If a chunk_specification is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the chunk_specification is an /integer_/simple_expression, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a discrete_subtype_definition is present, the elaboration elaborates the discrete_subtype_definition, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the chunk_specification, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised. For a loop statement that has an iteration scheme including a loop_parameter_specification, after elaborating the chunk_specification, if any, the loop_parameter_specification is elaborated. This elaboration elaborates the discrete_subtype_definition, which defines the subtype of the loop parameter. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a /sequential/ loop), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. If a chunk_specification with a discrete_subtype_definition is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters. *************************************************************** From: Randy Brukardt Sent: Monday, November 26, 2018 10:22 PM Thanks for the wording. Three minor quibbles. First, you have "(a /parallel/ loop)". But the term we're defining here is "parallel loop", not just parallel. So the italics should include "loop" -- that is "(a /parallel loop/)". The same applies to "sequential loop". Second, you dropped part of the introduction, specifically "For [the execution of] a loop_statement..." The "the execution of" part seems needed to be consistent with the wording in the rest of the clause. (See while loops and unconditional loops). I presume you dropped it because it is weirdish to talk about elaboration of a chunk_specification before describing any part of the execution of a loop. However, I've convinced myself that it is OK, as the elaboration of a chunk_specification applies to a number of kinds of loops (it's supposed to apply to the "of" form loops, I think; Brad needs to include that in his AI12-0266-1 if it isn't there yet). While the following paragraph applies only to the execution of one kind of loop. (Side note: splitting that paragraph into a paragraph that is general, and a paragraph that talks about loop parameters, should help out Brad, because he only wants the first part anyway.) Third, a number of terms that were previously syntax terms lost their underscores. I put them back, seeing no reason to make unnecessary changes. I won't mention that a number of sentences end with an pair of blanks, and others with a single blank. :-) *************************************************************** From: Randy Brukardt Sent: Monday, November 26, 2018 10:36 PM One last thought on this rewording. Nowhere in this wording do we say when the loop parameter (or parameters) are created. That isn't very important (as there is no side-effects from such creation, as noted by an AARM Note), but it still seems strange. I wondered if we need a To Be Honest AARM note to say that we don't describe exactly when each loop parameter is created, since it doesn't have any visible effect, but it does have to be done before the associated iteration starts. Or something like that. Thoughts? *************************************************************** From: Tucker Taft Sent: Tuesday, November 27, 2018 9:29 AM > One last thought on this rewording. Nowhere in this wording do we say > when the loop parameter (or parameters) are created. That isn't very > important (as there is no side-effects from such creation, as noted by > an AARM Note), but it still seems strange. I wondered if we need a To > Be Honest AARM note to say that we don't describe exactly when each > loop parameter is created, since it doesn't have any visible effect, > but it does have to be done before the associated iteration starts. Or > something like that. Thoughts? TBH sounds like the right solution. *************************************************************** From: Tucker Taft Sent: Tuesday, November 27, 2018 9:27 AM > Thanks for the wording. > > Three minor quibbles. > > First, you have "(a /parallel/ loop)". But the term we're defining > here is "parallel loop", not just parallel. So the italics should > include "loop" -- that is "(a /parallel loop/)". The same applies to > "sequential loop". Fine. > > Second, you dropped part of the introduction, specifically "For [the > execution of] a loop_statement..." The "the execution of" part seems > needed to be consistent with the wording in the rest of the clause. > (See while loops and unconditional loops). Yes I dropped it because it didn't seem to make sense any more. > I presume you dropped it because it is weirdish to talk about > elaboration of a chunk_specification before describing any part of the > execution of a loop. > However, I've convinced myself that it is OK, as the elaboration of a > chunk_specification applies to a number of kinds of loops (it's > supposed to apply to the "of" form loops, I think; Brad needs to > include that in his > AI12-0266-1 if it isn't there yet). While the following paragraph > applies only to the execution of one kind of loop. > > (Side note: splitting that paragraph into a paragraph that is general, > and a paragraph that talks about loop parameters, should help out > Brad, because he only wants the first part anyway.) OK. I am not sure what you are saying here -- perhaps if I saw your rewording it would be obvious. > Third, a number of terms that were previously syntax terms lost their > underscores. I put them back, seeing no reason to make unnecessary changes. Make sense. > I won't mention that a number of sentences end with an pair of blanks, > and others with a single blank. :-) Yes, let's not mention that... ;-) *************************************************************** From: Randy Brukardt Sent: Tuesday, November 27, 2018 8:22 PM ... > > Second, you dropped part of the introduction, specifically "For [the > > execution of] a loop_statement..." The "the execution of" part seems > > needed to be consistent with the wording in the rest of the clause. > > (See while loops and unconditional loops). > > Yes I dropped it because it didn't seem to make sense any more. In a vacuum, surely. In the context of the entire Dynamic Semantics section for this subclause, it seems wrong without it (there then would be no explanation of the execution of standard for loops, but there is for while loops and plain loops). > > I presume you dropped it because it is weirdish to talk about > > elaboration of a chunk_specification before describing any part of > > the execution of a loop. > > However, I've convinced myself that it is OK, as the elaboration of > > a chunk_specification applies to a number of kinds of loops (it's > > supposed to apply to the "of" form loops, I think; Brad needs to > > include that in his > > AI12-0266-1 if it isn't there yet). While the following paragraph > > applies only to the execution of one kind of loop. > > > > (Side note: splitting that paragraph into a paragraph that is > > general, and a paragraph that talks about loop parameters, should > > help out Brad, because he only wants the first part anyway.) > > OK. I am not sure what you are saying here -- perhaps if I saw your > rewording it would be obvious. The above is confusing. I was just pointing out that most of the wording for chunk_specifications should apply to all kinds of parallel loops (the elaboration, meaning in terms of chunks, and the check for nonzero all apply to all parallel for loops), while the rules about the loop parameter only apply to discrete "in" for loops. "of" loops don't even have loop parameters per-se, and "in" cursor loops have their own set of rules for managing the loop parameters. In particular, none of those other loop types have ordering for their parameters, so talking about "non-overlap" and "increasing order" is nonsense for them. (Maybe the array loop can talk about that in terms of the index, but the others get their chunks from the user-defined interface that we've been polishing over the last several meetings.) I'm certain that ultimately we intend to have parallel versions of all four kinds of "for" loops, even though this AI (and AI12-0119-1 before it) only contemplates parallel discrete "in" for loops. Brad supposedly is defining those other kinds of loops in AI12-0266-1; the less he has to modify this (AI12-0251-1/AI12-0294-1) wording in order to do that sensibly, the better off we'll be. (It would be madness to not have chunk_specifications on those other kinds of loops, so I'm not even considering that.) *************************************************************** From: Tucker Taft Sent: Tuesday, November 27, 2018 8:55 PM > ... >>> Second, you dropped part of the introduction, specifically "For [the >>> execution of] a loop_statement..." The "the execution of" part seems >>> needed to be consistent with the wording in the rest of the clause. >>> (See while loops and unconditional loops). >> >> Yes I dropped it because it didn't seem to make sense any more. > > In a vacuum, surely. In the context of the entire Dynamic Semantics > section for this subclause, it seems wrong without it (there then > would be no explanation of the execution of standard for loops, but > there is for while loops and plain loops). It may be that we can just sneak in the "For the execution of a ... at the beginning of the second paragraph. >>> I presume you dropped it because it is weirdish to talk about >>> elaboration of a chunk_specification before describing any part of >>> the execution of a loop. >>> However, I've convinced myself that it is OK, as the elaboration of >>> a chunk_specification applies to a number of kinds of loops (it's >>> supposed to apply to the "of" form loops, I think; Brad needs to >>> include that in his >>> AI12-0266-1 if it isn't there yet). While the following paragraph >>> applies only to the execution of one kind of loop. >>> >>> (Side note: splitting that paragraph into a paragraph that is >>> general, and a paragraph that talks about loop parameters, should >>> help out Brad, because he only wants the first part anyway.) >> >> OK. I am not sure what you are saying here -- perhaps if I saw your >> rewording it would be obvious. > > The above is confusing. Perhaps you were saying that it is good that I *already* split it up into multiple paragraphs. At first I presumed you wanted it to be split further, but maybe you are simply acknowledging that the split I proposed is useful for other reasons as well. > I was just pointing out that most of the wording for > chunk_specifications should apply to all kinds of parallel loops (the > elaboration, meaning in terms of chunks, and the check for nonzero all > apply to all parallel for loops), while the rules about the loop > parameter only apply to discrete "in" for loops. "of" loops don't even > have loop parameters per-se, and "in" cursor loops have their own set > of rules for managing the loop parameters. In particular, none of > those other loop types have ordering for their parameters, so talking > about "non-overlap" and "increasing order" > is nonsense for them. (Maybe the array loop can talk about that in > terms of the index, but the others get their chunks from the > user-defined interface that we've been polishing over the last several > meetings.) > > I'm certain that ultimately we intend to have parallel versions of all > four kinds of "for" loops, even though this AI (and AI12-0119-1 before > it) only contemplates parallel discrete "in" for loops. Brad > supposedly is defining those other kinds of loops in AI12-0266-1; the > less he has to modify this > (AI12-0251-1/AI12-0294-1) wording in order to do that sensibly, the > better off we'll be. (It would be madness to not have > chunk_specifications on those other kinds of loops, so I'm not even > considering that.) Agreed. *************************************************************** From: Randy Brukardt Sent: Tuesday, November 27, 2018 9:07 PM ... > It may be that we can just sneak in the "For the execution of a ... at > the beginning of the second paragraph. That's what I did. Not sure if the rest makes complete sense with that added, but that's why we review what I do at meetings. :-) *************************************************************** From: Randy Brukardt Sent: Tuesday, November 27, 2018 1:07 AM During the Lexington meeting, we had some discussion about the compatibility of Nonblocking => True and Yield => True. The rough draft of the minutes says on this: We then discuss whether Nonblocking True is incompatible with Yield True. Randy says that the Legality Rule 9.5(57/5) will fail in that case (the implicit Yield is illegal in a Nonblocking => True routine). We then get hung up on whether that is going to cause a problem in an expanded generic body. Legality Rules aren't rechecked in bodies. We decide to add an explicit rule to ensure that no subprogram has Nonblocking => True and Yield => True. The added rule was added to the end of the Static Semantics section defined the aspect, and reads: If the Nonblocking aspect (see 9.5) of the associated callable entity is statically True, the Yield aspect shall not be specified as True. However, this doesn't handle the case where the Nonblocking aspect is based on a property of one or more actuals for generic formal parameters. For instance, if we have something like: generic type Priv is private; with procedure Munge (Obj : in out Priv); package Gen is procedure Proc1 (Obj : in out Priv) with Nonblocking => Munge'Nonblocking, Yield => True; private procedure Proc2 (Obj : in out Priv) with Nonblocking => Munge'Nonblocking, Yield => True; end Gen; package body Gen is procedure Proc3 (Obj : in out Priv) with Nonblocking => Munge'Nonblocking, Yield => True; end Gen; All of Proc1, Proc2, and Proc3 would be declared this way if they intend to call Munge in their implementation. These generic units are legal with the rule as currently written, since Munge'Nonblocking is not static inside the generic unit. It only becomes static in the instance (I'll ignore the case of the instance being given inside of another generic with the actual being a formal of that generic so no one's head explodes; it doesn't cause any additional problems). Consider an instance with the actual for Munge being Nonblocking. Ada says that by default a Legality Rule is only enforced in the visible part of the specification of the instance, so the instance would be illegal because of Proc1. However, if Proc1 is commented out, the instance would be legal, even though Proc2 and Proc3 clearly violate the rule. For Proc2, we need the usual generic boilerplate. I'd suggest that we move the existing rule to an actual Legality Rules section before adding the boilerplate; otherwise, it would be very strange to try to apply it to something not explicitly marked as a Legality Rule. For Proc3, we need an assume-the-worst rule, as Legality Rules are never enforced in generic bodies. The easiest such rule that I can think of is to assume, for the purposes of the original rule, that any nonstatic Nonblocking attribute has the value True in a generic body. With such a rule, we can avoid the usual boilerplate for dealing with generic child units, since any generic child unit is also generic, and thus the body is a generic body. (By saying "nonstatic", we're including anything not known in the generic body; since only Nonblocking attributes that depend on an entity declared in a generic could be nonstatic, that seems good enough. If the rule went too far in some obscure case, it would be erring on the side of correctness. So I'd recommend that the wording of this aspect get changed to [I'm showing all of it except the Dynamic Semantics]: Add after D.2.1(1.5/2) For a noninstance subprogram (including a generic formal subprogram), a generic subprogram, or an entry, the following language-defined aspect may be specified with an aspect_specification (see 13.1.1): Yield The type of aspect Yield is Boolean. If directly specified, the aspect_definition shall be a static expression. If not specified (including by inheritance), the aspect is False. If a Yield aspect is specified True for a primitive subprogram S of a type T, then the aspect is inherited by the corresponding primitive subprogram of each descendant of T. Legality Rules If the Yield aspect is specified for a dispatching subprogram that inherits the aspect, the specified value shall be confirming. If the Nonblocking aspect (see 9.5) of the associated callable entity is statically True, the Yield aspect shall not be specified as True. For a callable entity that is declared within a generic body, this rule is checked assuming that any nonstatic Nonblocking attributes in the expression of the Nonblocking aspect of the entity are statically True. AARM Reason: The second sentence here is an assume-the-worst rule. The only Nonblocking attributes that are nonstatic are those that depend, directly or indirectly, on the nonblocking aspect of a generic formal parameter. We have to assume these might in fact have the value True if given an appropriate actual entity. In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit. --- I moved the other Legality Rule also to this new Legality Rules section; it would be weird if it was left in Static Semantics. Note that the boilerplate also applies to this first rule. It could depend on an inherited subprogram that came only from an actual type passed to a formal parameter; thus a recheck could be necessary. The case would be quite obscure -- common for rechecks -- but still needs checking. Thoughts on this redo? It's a pretty big change, and rather obscure, so I think it would best go into the clean-up AI. *************************************************************** From: Tullio Vardanega Sent: Tuesday, November 27, 2018 4:33 AM Yup: with brain nearly exploding, I would go with your rewrite, Randy. *************************************************************** From: Tucker Taft Sent: Tuesday, November 27, 2018 9:19 AM Agreed, on both counts. ;-) *************************************************************** From: Randy Brukardt Sent: Thursday, December 6, 2018 4:43 PM When I was rereading this new wording, I had a couple of questions: [Note: the other question is in AI12-0298-1.] (1) One of the Legality Rule paragraphs reads: If multiple Conflict_Check_Policy pragmas apply to a given construct, the conflict check policy is determined by the one in the innermost enclosing region. If no such Conflict_Check_Policy pragma exists, the policy is Parallel_Conflict_Checks (see below). When I read this, I read the second sentence as being an exceptional case for the first sentence. But I don't believe that is the intent -- we had intended that the policy always defaults to Parallel_Conflict_Checks. Having thought about this far more than is healthy :-), I'm convinced that the (immediate) problem is the word "such" in this second sentence. So one fix would be to drop that. Another fix would be to simply make these two sentences separate paragraphs. And a third possibility would be to reword the second sentence to make it a bit clearer: If no Conflict_Check_Policy pragma applies to a construct, the policy is Parallel_Conflict_Checks (see below). And a fourth choice would to both reword and separate. And there's always the choice of saying that Randy is seeing things again. ;-) Any preference? (It would be nice to put this in the clean-up AI for the upcoming meeting, but it can wait.) *************************************************************** From: Tucker Taft Sent: Thursday, December 6, 2018 8:38 PM > .... > > If no Conflict_Check_Policy pragma applies to a construct, the policy > is Parallel_Conflict_Checks (see below). I like this one. The first sentence talks about when two or more apply. The second sentence talks about when zero apply. There is no ambiguity if there is only one. > ... > > Any preference? (It would be nice to put this in the clean-up AI for > the upcoming meeting, but it can wait.) See above. ***************************************************************