Version 1.2 of ai12s/ai12-0309-1.txt

Unformatted version of ai12s/ai12-0309-1.txt version 1.2
Other versions for file ai12s/ai12-0309-1.txt

!standard 11.5(10)          19-02-05 AI12-0309-1/01
!standard 11.5(19)
!standard 11.5(20)
!standard 11.5(22)
!standard 11.5(24)
!class binding interpretation 19-02-05
!status work item 19-02-05
!status received 18-11-28
!priority Low
!difficulty Easy
!qualifier Omission
!subject Missing checks for pragma Suppress
!summary
Check names are defined for various checks that don't have them.
!question
AI12-0251-1 adds a check that the number of chunks in a chunk_specification is not zero or negative. Should this check have a check name and be suppressible? (Yes.)
!recommendation
(See Summary.)
!wording
Modify 11.5(10):
The following checks correspond to situations in which the exception Constraint_Error is raised upon failure {of a language-defined check}.
Modify 11.5(19):
The following checks correspond to situations in which the exception Program_Error is raised upon failure {of a language-defined check}.
Add after 11.5(20):
Program_Error_Check
Check that there is not an error in the logic of the program: that subtypes with predicates are not used to index an array in a generic unit; that the maximum number of chunks is greater than zero; that the default value of an out parameter is convertable; that there is misuse of functions in a generic with an class-wide actual type; that there are not colliding External_Tag values; that there is misuse of operations of unchecked union types.
[Note to editor: One needs to add @IndexCheck{Program_Error_Check} to each of these places in the draft RM so that the index entries are created for them. It doesn't pay to do that until the name is decided.]
Modify 11.5(22):
The following check corresponds to situations in which the exception Storage_Error is raised upon failure {of a language-defined check}.
Add before 11.5(24):
The following check corresponds to situations in which the exception Tasking_Error is raised upon failure of a language-defined check.
Tasking_Check
Check that all tasks activated successfully. Check that a called task has not yet terminated.
Modify 11.5(24):
The following check corresponds to all situations in which any predefined exception is raised {upon failure of a check}.
Modify 11.5(25.a):
All_Checks includes both language-defined and implementation-defined checks {those with names}.{ It does not include, however, explicit raises of predefined exceptions, nor those propagated from language-defined subprograms.}
[Editor's note: The RM consistently (with a handful of exceptions) uses the wording "Blah_Error is propagated" rather than "a check is made, and Blah_Error is raised if it fails" when talking about language-defined subprograms. Note that assertions like preconditions do in fact use check wording and thus are fair game for suppression.]
!discussion
For Ada 95 and Ada 2005, we tried to ensure that all of the language-defined checks have an associated check name that can be used in pragma Suppress. However, we haven't worried about that for Ada 2012 and (until now) Ada 2020.
Following are the places in the core of the RM where language-defined checks are made but don't have check names:
Tasking_Error: 9.2(5): failure of task activation. 9.5.3(21): calling a terminated task.
Assertion_Error: 11.4.2(18/3): This isn't really a check, just the result of pragma Assert. We have Assertion_Policy to turn these off, so we can ignore this.
Program_Error: 3.2.4(29.1/4): use of types with predicates in generic bodies. 5.5(8.1/5): zero or fewer chunks in a chunk specification. 6.4.1(13.4/4): an out parameter with Default_Value, and the actual is a view conversion of an unrelated type that does not have Default_Value. 12.5.1(23.3/2): a primitive function of T raises P_E for a class-wide actual. 13.3(75.1/3): colliding external_tag values. B.3.3(22/2): Operations of unchecked_unions without inferable discriminants.
Pragma Detect_Blocking is in Annex H, so we aren't covering that here, and it's not really a check anyway (it is written as mandated result for a bounded error case).
Note that there are a number of exceptions raised by language rules which are not associated with checks and which cannot be suppressed. These were mistakenly indexed as checks in previous versions of the standard; they're now indexed individually. (It's still possible to look in the index to find all language-defined reasons that cause the implementation to raise an exception, the reasons are just now categorized into checks, bounded errors, and other reasons. This does not include exceptions raised by language-defined units, for which exception propagation never has been indexed consistently; the handful of existing index entries have been removed to avoid confusion.)
---
We've proposed new check names that are singular (Tasking_Check), rather than plural (Tasking_Checks) to be consistent with existing practice. All of the existing names are singular, although most cover multiple kinds of checks (and certainly apply to multiple actual checks in a program).
For example, range_check includes 28 different checks (according to the index), including things that are only vaguely related to ranges (including 'Value syntax checks!). Allocator_Check includes four rather different checks, including one that only applies to subpools. Index_Check includes various checks on array aggregates, as well as actual indexing.
If we made the new names plural, users would have to look up every name to see whether it is "Something_Check" or "Something_Checks". That difference is not something that would be easy to remember, especially for something that isn't written very often.
An alternative would be to make all of the names end in "_Checks", and put the existing names that end in "_Check" into Annex J. This would work, but seems would be able to remember that
---
Additionally, the wording in 11.5 associated with the check names can make a causal reader think that these apply to cases that are not intended (explicit raises, exceptions raised by language-defined units, and so on). We correct the wording to avoid that. (We worry about this as this list of checks is often referred to directly from the index without looking at the complete text of the subclause. People shouldn't have to read the whole subclause to understand it in such cases.)
---
We considered whether to include some sort of check names for bounded error cases. These should inform the compiler that no detection of bounded errors is desired (which would be especially useful for applications that don't want exceptions raised). However, the semantics are unclear. At least some respondents would want different semantics for bounded errors that occur (specifically, that the compiler chose one of the non-detection results in that case) rather than just saying that the code is erroneous. Others think that Suppress(Bounded_Checks) means that any bounded error that occurred should be erroneous. Since it isn't important to answer this question now, we pass.
!ASIS
No ASIS effect.
!ACATS test
!appendix

From: Randy Brukardt
Sent: Friday, November 16, 2018  7:41 PM

This AI has:

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.

Is this check Suppressible? If so, what check name is it associated with??
And if not, that's pretty weird. (I noticed this because I have index all 
checks, and it isn't obvious as to what to index it under.) The options for 
Program_Error are Accessibility_Check, Allocation_Check, and 
Elaboration_Check. It seems like there ought to be some catch-all check 
(like "Bug_Check"), as there seem to be other cases that raise Program_Error 
but don't have a check name. Probably a separate AI if the group thinks this 
is a good idea (or even a neutral idea). Note that it seems that All_Checks 
covers everything, even those things that don't have a name.

Aside: All_Checks is lead-in by the following text:

The following check corresponds to all situations in which any predefined 
exception is raised.

But this is wrong, since (even if we decide that IO_Exceptions aren't
covered) we don't want suggest that there is any suppression of exceptions 
raised by language-defined libraries (even if that is Program_Error). And 
we certainly don't want to imply that one can suppress things that aren't 
checks (specifically the case completeness exception for case 
statements/expressions and variants; I'd guess that Detect_Blocking also 
falls into this category). Nor do want to imply that this might apply to 
an explicit raise statement for a predefined exception (which would be 
complete madness).

It should at least say "is raised by a check". Or maybe "... all situations 
where a check raises any predefined exception".
The other lead-ins have similar issues. Note that the formal definition 
seems to avoid this issue, and these are marked as redundant, so arguably 
there's no real problem. But I have to wonder the value of misleading text 
in the RM.

---

A for-the-record point: The AI defines "chunk_parameter" (WITH an 
underscore), but this seems to be an English term. There's a second use that 
is in italics for no obvious reason (there should only be one definition of 
a term). It rather looks like this was originally a syntax term and then the 
syntax was removed but the underscore left behind. So I removed the 
underscore from both uses and the italics from the second use.
[This is discussing AI12-0251-1 - Editor.]

****************************************************************

From: Tucker Taft
Sent: Friday, November 16, 2018  9:25 PM

...
> Is this check Suppressible? If so, what check name is it associated with??
> And if not, that's pretty weird. (I noticed this because I have index 
> all checks, and it isn't obvious as to what to index it under.) The 
> options for Program_Error are Accessibility_Check, Allocation_Check, 
> and Elaboration_Check. It seems like there ought to be some catch-all 
> check (like "Bug_Check"), as there seem to be other cases that raise 
> Program_Error but don't have a check name. Probably a separate AI if 
> the group thinks this is a good idea (or even a neutral idea). Note 
> that it seems that All_Checks covers everything, even those things that 
> don't have a name.

I would agree this should be a separate AI.  No need to bog this one down.

> It should at least say "is raised by a check". Or maybe "... all 
> situations where a check raises any predefined exception".
> The other lead-ins have similar issues. Note that the formal 
> definition seems to avoid this issue, and these are marked as 
> redundant, so arguably there's no real problem. But I have to wonder 
> the value of misleading text in the RM.

I agree that All_Checks should restrict itself to exceptions propagated as
the result of a check.

...
> A for-the-record point: The AI defines "chunk_parameter" (WITH an 
> underscore), but this seems to be an English term. There's a second 
> use that is in italics for no obvious reason (there should only be one 
> definition of a term). It rather looks like this was originally a 
> syntax term and then the syntax was removed but the underscore left 
> behind. So I removed the underscore from both uses and the italics from 
> the second use.

OK.

****************************************************************

From: Bob Duff
Sent: Saturday, November 17, 2018  1:59 PM

> Aside: All_Checks is lead-in by the following text:
> 
> The following check corresponds to all situations in which any 
> predefined exception is raised.

I agree it was not the intent to suppress an explicit "raise Program_Error;" 
in user code.  But I think it was the intent to allow suppression of things 
like Tasking_Error detected in the run-time library, which I don't think 
have check names.

I think this is insufficiently broken to be worth fixing.  If you show me 
a compiler that does something unreasonable, I'll change my mind.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, November 20, 2018  1:45 PM

> I agree it was not the intent to suppress an explicit "raise 
> Program_Error;" in user code.  But I think it was the intent to allow 
> suppression of things like Tasking_Error detected in the run-time 
> library, which I don't think have check names.

That may have been the Ada 9x team's intent, but the wording of the Standard 
is quite clear that run-time library exceptions aren't "checks". And the 
introduction of 11.5 is quite clear (now, that wording might have been changed 
by Ada 2005) that pragmas Suppress and Unsuppress are for managing "checks" 
and nothing else.

GNAT's "Container_Checks" is formally wrong, because what it is suppressing 
is not a check. (Not that anyone could or would want to try to prevent such 
a check name.) Interestingly, the "Container_Check" suppression that
AI12-0112-1 has is formally correct, since all it does is suppress 
preconditions, and preconditions ARE checks (ones that explicitly excluded 
from All_Checks).

> I think this is insufficiently broken to be worth fixing.  If you show 
> me a compiler that does something unreasonable, I'll change my mind.

Arguably, it's not "broken", since the introductory text to the clause is 
clear that this only applies to "checks". It's just misleading for casual 
reading. Since you have the wrong (compared to the formal wording) mental 
model of these pragmas, it's clear that people (even ones that should know
better) are being misled.

Anyway, I'm clearly going to need to do something about the checks that 
don't have suppression names, and I can put some rewordings into that AI,
and then we can discuss it for an hour. ;-)

BTW, I think there is a more significant question, and that is whether 
Bounded Errors are suppressible. Typically, Bounded Errors aren't 
described as checks, but they can raise an exception if the compiler has 
decided to enforce them (usually, they say "if the error is detected, then 
Blah_Error is raised"). For instance, reading an invalid value can raise 
Constraint_Error or Program_Error (see 13.9.1(9)). One could imagine a 
compiler inserting code to make such "detection", and one also can imagine 
wanting to eliminate it.

****************************************************************

From: Tucker Taft
Sent: Tuesday, November 20, 2018  1:58 PM

> ...
> BTW, I think there is a more significant question, and that is whether 
> Bounded Errors are suppressible. Typically, Bounded Errors aren't 
> described as checks, but they can raise an exception if the compiler 
> has decided to enforce them (usually, they say "if the error is 
> detected, then Blah_Error is raised"). For instance, reading an 
> invalid value can raise Constraint_Error or Program_Error (see 
> 13.9.1(9)). One could imagine a compiler inserting code to make such 
> "detection", and one also can imagine wanting to eliminate it.

I am uncomfortable with pragma Suppress having any effect on Bounded 
Errors, but I suppose it would be fine for the compiler to decide to 
produce one effect rather than another of the effects allowed for a given 
Bounded Error.  That is, a "suppress" pragma might be considered as an 
indication that exceptions are not desirable in this application, and 
hence if there is a permitted outcome of a Bounded Error that does not 
raise an exception, a "friendly" compiler might go that route.  But I 
definitely don't think a Suppress pragma should imply that a Bounded 
Error might produce an effect that is not one of the permitted effects 
for the error.

****************************************************************

From: Bob Duff
Sent: Tuesday, November 20, 2018  5:17 PM

> But I definitely don't think a Suppress pragma should imply that a 
> Bounded Error might produce an effect that is not one of the permitted 
> effects for the error.

I don't see that.  I mean, if something normally raises an exception, then 
it's OK for pragma Suppress to make it erroneous, but if it normally raises
an exception or does X, that's not OK?  Heh?

Consider:

    type T is range 1..10;
    type Arr is array(T) of ...;
    X: T;
    A: Arr := (others => ...);
    ... -- code that might or might not initialize X
    A(X+1) := ...; -- exception raised here?

If X = 10, an exception is raised.  If X is uninitialized, that's a bounded 
error, and if it happens to be 11 (invalid), an exception is raised.

Now if we suppress checks, then:

If X = 10, it's erroneous -- we can overwrite arbitrary memory.  If X is 
uninitialized and it happens to be 11 (invalid), you insist that an 
exception be raised.  It cannot overwrite arbitrary memory.  So, in fact, 
the check that "X+1 in 1..10" cannot be removed by Suppress.

Am I misinterpreting what you meant?

****************************************************************

From: Tucker Taft
Sent: Tuesday, November 20, 2018  9:50 PM

>> But I definitely don't think a Suppress pragma should imply that a 
>> Bounded Error might produce an effect that is not one of the 
>> permitted effects for the error.
> 
> I don't see that.  I mean, if something normally raises an exception, 
> then it's OK for pragma Suppress to make it erroneous, but if it 
> normally raises an exception or does X, that's not OK?  Heh?

What I was suggesting was that if a bounded error normally raises an 
exception or does X, and you suppress all_checks, it still should 
"raise an exception or do X," but it would be fine if an implementation 
decided it will choose to always do X instead of raising an exception.  
But the implementation can't decide to do "Y" instead of "X" as a result 
of the Suppress.

> Consider:
> 
>    type T is range 1..10;
>    type Arr is array(T) of ...;
>    X: T;
>    A: Arr := (others => ...);
>    ... -- code that might or might not initialize X
>    A(X+1) := ...; -- exception raised here?
> 
> If X = 10, an exception is raised.  If X is uninitialized, that's a 
> bounded error, and if it happens to be 11 (invalid), an exception is 
> raised.
> 
> Now if we suppress checks, then:
> 
> If X = 10, it's erroneous -- we can overwrite arbitrary memory.  If X 
> is uninitialized and it happens to be 11 (invalid), you insist that an 
> exception be raised.  It cannot overwrite arbitrary memory.  So, in 
> fact, the check that "X+1 in 1..10" cannot be removed by Suppress.
> 
> Am I misinterpreting what you meant?

Well the bounded errors allow it to proceed further using the invalid value.
Then later if you suppress the index check, and it would have failed the 
index check, then that is OK.

My point is that a pragma suppress all_checks does not cause a program's 
execution to become immediately erroneous if it reads an uninitialized 
variable (because that is a "bounded" error rather than a check), whereas 
if a check would have failed and you have suppressed it, then than can 
lead to erroneous execution.  Perhaps not a meaningful distinction in 
most cases, but I think there is a distinction in theory.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 6, 2019  2:08 AM

I had given myself a task to look at the RM for all of the core checks which 
do not have check names. In Ada 2005, we tried to ensure that pretty much all
of the checks (except Tasking_Errors, for some reason) had names. But we 
haven't continued that for Ada 2012 and Ada 2020.

I used the index of exceptions raised; I ended up spending several hours 
redoing that to remove things that aren't checks (like Implementation
Advice) from the list of exceptions raised by checks, the cases where 
exceptions are raised that aren't checks (like case statements and falling 
out of a function) and can't be suppressed, and also all of the exceptions 
raised by bounded errors (which I indexed separately, since what to do with 
those is another question altogether).

For tasking error, the name seems like it ought to be Tasking_Check. (I see 
no reason that this shouldn't have a name, even if it almost never can be 
suppressed in practice.)

For Program_Error, however, I have a bunch of rather unrelated stuff that 
seems to defy coming up with a good name for. Here's the list:

Program_Error:
  3.2.4(29.1/4): use of types with predicates in generic bodies.
  5.5(8.1/5): zero or fewer chunks in a chunk specification.
  6.4.1(13.4/4): an out parameter with Default_Value, and the actual is a 
    view conversion of an unrelated type that does not have Default_Value.
  12.5.1(23.3/2): a primitive function of T raises P_E for a class-wide actual.
  13.3(75.1/3): colliding external_tag values.
  B.3.3(22/2): Operations of unchecked_unions without inferable discriminants.

This seems like "Bunch_o_Checks". Naming them individually seems like overkill 
(Chunk_Check, Tag_Name_Check, Unchecked_Union_Check, Predicate_Usage_Check, 
Out_View_Conversion_Check). Leaving them unnamed seems bizarre. I suppose we
could call them "Other_Check" (all of these names are singular, and I think we
want to continue that -- all of the existing names cover many different 
checks, so there's no reason to vary from that -- it would be hard to know 
when to make the name plural and when singular if we mix them.

I might have missed some if they aren't indexed at all; there are too many 
uses of Program_Error and Constraint_Error in AARM notes and bounded errors 
and in language-defined units to inspect them all manually. (I did find 
several that were missing part or all of the index entries, so it wouldn't 
surprise me if there were others). 

Note that I didn't find any checks raising Constraint_Error that don't fit 
into the existing check names.

Any thoughts, other ideas??

****************************************************************

From: Jean-Pierre Rosen
Sent: Wednesday, February 6, 2019  10:51 AM

> This seems like "Bunch_o_Checks". Naming them individually seems like 
> overkill (Chunk_Check, Tag_Name_Check, Unchecked_Union_Check, 
> Predicate_Usage_Check, Out_View_Conversion_Check). Leaving them 
> unnamed seems bizarre. I suppose we could call them "Other_Check" (all 
> of these names are singular, and I think we want to continue that -- 
> all of the existing names cover many different checks, so there's no 
> reason to vary from that -- it would be hard to know when to make the 
> name plural and when singular if we mix them.

Why not Program_Errors_Checks? Not because of the name of the exception, 
but because they are all errors in the program's logic.

****************************************************************

From: Tucker Taft
Sent: Wednesday, February 6, 2019  10:51 AM

I would suggest simply "Program_Error_Checks."  There is a precedent for 
using plural in All_Checks, and this seems analogous.

****************************************************************

From: Tucker Taft
Sent: Wednesday, February 6, 2019  11:52 AM

Great minds and all that...  But I would prefer "Program_Error_Checks" 
-- the double plural of "Program_Errors_Checks" grates on my ears.

****************************************************************

From: Steve Baird
Sent: Wednesday, February 6, 2019  12:01 PM

> But I would prefer "Program_Error_Checks" -- the double plural of 
> "Program_Errors_Checks" grates on my ears.

What he said.

****************************************************************

From: Jean-Pierre Rosen
Sent: Wednesday, February 6, 2019  12:29 PM

Yes; but I used the plural to make clear that the name was not the name of 
the exception.

****************************************************************

From: Tucker Taft
Sent: Wednesday, February 6, 2019  3:06 PM

Be that as it may... ;-)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 6, 2019  5:43 PM

> I would suggest simply "Program_Error_Checks."  There is a precedent 
> for using plural in All_Checks, and this seems analogous.

I disagree; all of these names (except All_Checks) should be singular for 
consistency. Almost all of the existing names cover a large number of 
different checks, and still have singular names.

For example, range_check includes 28 different checks (according to the 
index), including things that are only vaguely related to ranges (including 
'Value syntax checks!). Allocator_Check includes four rather different checks, 
including one that only applies to subpools. Index_Check includes various 
checks on aggregates, as well as actual indexing. And so on.

While I would prefer that ALL of the names be plural (we're almost always 
talking about the pragma applying to multiple checks), that would be changing 
things (and potentially breaking things) for no good reason. So I think all 
of the names have to be singular, lest one has to look up every name to see 
if it is singular or plural before using it.

****************************************************************

From: Tucker Taft
Sent: Wednesday, February 6, 2019  7:12 PM

I can live with either Program_Error_Check or Program_Error_Checks.

I really don't like Program_Errors_Check or Program_Errors_Checks, though I 
understand JP's rationale behind the suggestion.

****************************************************************

Questions? Ask the ACAA Technical Agent