Version 1.26 of ais/ai-00224.txt

Unformatted version of ais/ai-00224.txt version 1.26
Other versions for file ais/ai-00224.txt

!standard 11.5(1)          03-02-17 AI95-00224/08
!standard 11.5(3)
!standard 11.5(4)
!standard 11.5(5)
!standard 11.5(6)
!standard 11.5(7)
!standard 11.5(8)
!standard 11.5(27)
!standard 11.5(29)
!standard J.10(00)
!class amendment 99-11-19
!status Amendment 200Y 03-02-17
!status ARG Approved 8-0-0 03-02-07
!status work item 99-11-19
!status received 99-11-19
!priority Medium
!difficulty Medium
!subject pragma Unsuppress
!summary
A pragma is introduced to require checking in a declarative region, irrespective of the use of pragma Suppress.
!problem
Ada code sometimes depends on the canonical checking semantics of the language. Consider, for instance, a non-negative integer saturation arithmetic package. The multiply operation might look like:
function "*" (Left, Right : Saturation_Type) return Saturation_Type is begin
return Integer(Left) * Integer(Right);
exception
when Constraint_Error =>
return Saturation_Type'Last;
end "*";
This function will not work properly without overflow checking. Ada 95 does not provide a way to indicate this to the compiler and programmers.
!proposal
A new pragma Unsuppress is defined.
pragma Unsuppress (identifier);
The identifier argument of Unsuppress is the same as Suppress. Unsuppress can be used in the same places as Suppress, with similar scoping rules.
Pragma Unsuppress revokes the permission to suppress a check, that is, it means that the given check must be performed.
!wording
Define "Checking pragmas" and add pragma Unsuppress to 11.5(1) ("Checking pragmas" is in italics):
Checking pragmas give an implementation instructions on handling language-defined checks. A pragma Suppress gives permission to an implementation to omit certain language-defined checks, while a pragma Unsuppress revokes the permission to omit checks.
Add pragma Unsuppress to 11.5(3-4), and remove the On parameter from Suppress:
The forms of checking pragmas are as follows:
pragma Suppress(identifier); pragma Unsuppress(identifier);
Change 11.5(5) to apply to checking pragmas:
A checking pragma is allowed only immediately within a declarative_part, immediately within a package_specification, or as a configuration pragma.
Change 11.5(6) to remove the reference to the On parameter:
The identifier shall be the name of a check.
Delete 11.5(7) (it only refers to the On parameter).
Change 11.5(8) to define the meaning of pragma Unsuppress and to remove the On parameter:
A checking pragma applies to the named check in a specific region (see below), and applies to all entities in that region. A checking pragma given in a declarative_part or immediately within a package_specification applies from the place of the pragma to the end of the innermost enclosing declarative region. The region for a checking pragma given as a configuration pragma is the declarative region for the entire compilation unit to which it applies.
[If a checking pragma applies to a generic instantiation, then the checking pragma also applies to the instance. If a checking pragma applies to a call to a subprogram that has a pragma Inline applied to it, then the checking pragma also applies to the inlined subprogram body.]
AARM Proof: An instance is a copy of the generic at the place of the instantiation (see 12.3(12)); and inlined subprogram bodies are expanded at the place of the call (see 6.3.2). This rule just makes it clear that we meant that.
AARM Discussion: The rule means that any checks suppressed at the point of the instantiation or called are suppressed in the instance body or inlined subprogram body. Permissions that are revoked at that point are not included, of course. This is in addition to any checks that may be suppressed in the generic body or subprogram body. Note that implementations are not required to suppress checks in these contexts, as check suppression is always a permission, not a requirement.
A pragma Suppress gives permission to an implementation to omit the named check (or every check in the case of All_Checks) for any entities to which it applies. If permission has been given to suppress a given check, the check is said to be suppressed.
A pragma Unsuppress revokes the permission to omit the named check (or every check in the case of All_Checks) given by any pragma Suppress that applies at the point of the pragma Unsuppress. The permission is revoked for the region to which the pragma Unsuppress applies. If there is no such permission at the point of a pragma Unsuppress, then the pragma has no effect. [A later pragma Suppress can renew the permission.]
AARM Note: Unsuppress does not have an effect on the check suppression implicit in pragma Unchecked_Union. However, implementations should insure that it does apply to suppression which comes from compiler options (preferably by modeling them as pragma Suppress configuration pragmas).
Change 11.5(27) to apply to checking pragmas:
An implementation is allowed to place restrictions on checking pragmas, subject only to the requirement that pragma Unsuppress shall allow any check names supported by pragma Suppress. An implementation is allowed to add additional check names, with implementation-defined semantics. When Overflow_Check has been suppressed, an implementation may also suppress an unspecified subset of the Range_Checks.
An implementation may support an additional parameter on pragma Unsuppress similar to the one allowed for pragma Suppress (see J.XX). The meaning of such a parameter is implementation-defined.
Add an additional note after 11.5(29):
It is possible to give both a pragma Suppress and Unsuppress for the same check immediately within the same declarative_part. In that case, the last pragma given determines whether or not the check is suppressed. Similarly, it is possible to resuppress a check which has been unsuppressed by giving a pragma Suppress in an inner declarative region.
Add an entire new section in Annex J (obsolescent features) to describe the specific checking pragmas:
J.XX Specific Suppression of Checks
Pragma Suppress can be used to suppress checks on specific entities.
Syntax
The form of a specific Suppress pragma is as follows:
pragma Suppress(identifier, [On =>] name);
Legality Rules
The identifier shall be the name of a check (see 11.5). The name shall statically denote some entity.
For a specific Suppress pragma that is immediately within a package_specification, the name shall denote an entity (or several overloaded subprograms) declared immediately within the package_specification.
Static Semantics
A specific Suppress pragma applies to the named check from the place of the pragma to the end of the innermost enclosing declarative region, or, if the pragma is given in a package_specification, to the end of the scope of the named entity. The pragma applies only to the named entity, or, for a subtype, on objects and values of its type. A specific Suppress pragma suppresses the named check for any entities to which it applies (see 11.5). Which checks are associated with a specific entity is not defined by this standard.
AARM Discussion: Exactly which entit(ies) control whether a check is performed is not specified by the language. For example, in
pragma Suppress (Range_Check, On => A); A := B;
whether or not the range check is performed is not specified. The compiler may require that checks are suppressed on B or on the type of A in order to suppress the range check.
Implementation Permissions
An implementation is allowed to place restrictions on specific Suppress pragmas.
Note
An implementation may support an entity parameter on pragma Unsuppress (see 11.5).
!example
We can use pragma Unsuppress to insure that checking occurs in the saturation multiply function given earlier:
function "*" (Left, Right : Saturation_Type) return Saturation_Type is
pragma Unsuppress (Overflow_Check);
begin return Integer(Left) * Integer(Right); exception when Constraint_Error => return Saturation_Type'Last; end "*";
If there is a pragma Suppress for Overflow_Check effective in "*", the Unsuppress will revoke the permission to omit the checks, thus requiring the checks to be made. If there is no pragma Suppress, then the pragma Unsuppress is ignored.
!discussion
Ada 95 provides an easy way to suppress checking over large areas of program text. Pragma Suppress can be used in a package specification to apply to an entire package, or even as a configuration pragma to apply to the entire program.
It is common for production versions of applications to be delivered with checking suppressed (perhaps for better performance or smaller code size). If pragma Suppress is applied to an entire package or program, code that requires checking will start to fail. Ada code that depends on the canonical checking semantics is not common, but it occurs frequently enough that most Ada programmers have been bitten by this problem at one time or another.
The problem is made worse by the fact that Ada 95 does not provide any way to turn off pragma Suppress over a smaller, inner region of the program. Therefore, fixing the problem requires moving the pragma Suppresses to individual packages and/or subprograms, which is clearly error-prone.
The pragma proposed here can be used both as a preventative measure (to insure that the code continues to work if a later programmer applies Suppress to the unit) and as a repair when checks are suppressed where they are required.
Note that the pragma Suppress that causes problems may not be explicit; many compilers include an option switch that effectively adds pragma Suppress to the start of each compilation unit.
The presence of pragma Unsuppress has no effect on compiler optimization of checks. A compiler is still allowed to remove checks that it can prove will not fail. This is why the wording is expressed in terms of "revoking the permission to omit" rather than "requiring" checks.
Pragma Unsuppress is defined to affect checks suppressed by a pragma Suppress. This is necessary to support pragma Unchecked_Union, which is defined in terms of suppressing checks. The checks for pragma Unchecked_Union cannot be turned on as there is no discriminant value with which to make a check.
This proposal allows nested suppression of checks. That is, checks can be "resuppressed" inside of a region where checks are "unsuppressed" (required). This is necessary to prevent problems with code where the correctness depends on suppression of checks. (While such code is technically erroneous, in actual practice such does exist. We do not want to break it by being pedantic.) Such code would include a pragma Suppress. If checks could not be resuppressed, this code would fail if it was nested inside of a construct that contains an Unsuppress pragma, or if a Unsuppress configuration pragma was used. This would essentially be the current problem all over again, so the model where Unsuppress has precedence over Suppress was rejected.
Pragma Suppress can be inherited into other compilation units. In particular, a pragma Suppress used in a package specification also applies to the package body, and a pragma Suppress also applies to any subunits in the declarative region. This inheritance is not commonly implemented by Ada 95 compilers. This is OK, as the permission to suppress checks can always be ignored. It appears that the situation for Unsuppress is different. If it fails to inherit properly, checks might be suppressed that should not be.
We considered eliminating inheritance from all of these programs, as it is preferable that a checking pragma be visible in any scope to which it applies. However, this is incompatible with both the existing language, and some existing implementation.
We also considered having Unsuppress not inherit, while leaving Suppress alone. This has the unfortunate property of having too different models for the pragmas. This means that checking can change simply by moving code, as in the following example:
package body P is pragma Suppress (All_Checks); pragma Unsuppress (Tag_Checks); procedure Proc is separate; end P;
In this model, Tag_Checks are suppressed in Proc depending on whether Proc is "inlined" into the package or separate.
A third alternative is to simply define inheritance to be implementation-defined. This was rejected due to the lack of portability and that it leaves the language no safer than the existing inheritance model.
Therefore, we have retained the inheritance model of Ada 95, and it applies to pragma Unsuppress as well as Suppress. The basic model is that a configuration checking pragma is equivalent to the same checking pragma given at the first possible place within the unit.
With this model, inheritance of Unsuppress is not a problem, even for implementations that do not implement inheritance. Recall that the rule for Unsuppress is that it revokes the permission to omit checks that currently exist, and it has no effect on checks that are suppressed later. Now, consider:
package P is pragma Unsuppress (Overflow_Check); procedure Proc; end P;
pragma Suppress (Overflow_Check); --(1) package body P is pragma Suppress (Overflow_Check); --(2) procedure Proc is ... end P;
Pragma (2) clearly occurs after the pragma Unsuppress, so the Unsuppress has no effect, and the check is suppressed. By the equivalence model, pragma (1) is equivalent to pragma (1).
It is important to note that pragma Unsuppress has no effect of its own. There only is a permission to omit checks or no permission to do. Essentially, an implementation which does not inherit the permission will always make the checks. This is identical to an implementation which does inherit the permission in the case when it is revoked (because then the checks are required). So, the only requirement is that an implementation inherit the permission or lack of one in the same way.
It has been suggested that an implementation which did not inherit would have problems with generic instances and inlined subprograms. But this is not true. If the subprogram or generic contains an explicit Suppress, that pragma should be honored in any implementation. If the subprogram or generic inherits the permission to suppress, and it contains an appropriate pragma Unsuppress, the checks must be made. But this must happen, even if the implementation does not inherit the permission, as in that case the checks would have been made in any instance.
The point of this discussion is that it is not necessary for implementations to change their inheritance semantics in order to implement Unsuppress.
If more than one checking pragma is given as configuration pragmas, the language does not specify the order in which they are applied. This means that the exact effect is unspecified as well (as the order of the pragmas could change their effect). Consider:
pragma Suppress (All_Checks); pragma Unsuppress (Storage_Check);
vs.
pragma Unsuppress (Storage_Check); pragma Suppress (All_Checks);
Whether or not Storage_Check is suppress depends on the order of the pragmas. This doesn't seem to be an important enough problem to worry about; Unsuppress should be used in local scopes, not as a configuration pragma.
Restrictions can be placed on pragma Unsuppress. This is necessary to avoid burdening implementations implementing items for which no Suppress support is provided. We do require that any check names supported for Suppress is also supported for Unsuppress, because it is important to be able to unsuppress checks suppressed over a larger area. Note that the reverse is not true; implementations can support more of Unsuppress than of Suppress if they desire.
Checking pragmas with an On parameter are moved in the obsolescent features section. That was done because these features are inherently non-portable, and we want to discourage their use.
Compiler surveys determined that the implementation of On parameters on pragma Suppress vary widely, even for implementations with the same target. It does not seem valuable to try to bring any portability to this area.
For instance, exactly which entit(ies) control when a check is performed is (purposely) not defined. In
A := B;
whether the range check is performed may depend whether checks are suppressed on A, B, or the type of A. For check suppression, this is not critical, as any code that would violate the checks is erroneous anyway (11.5(26)). On the other hand, not making a check that the programmer is depending on can cause the program to fail. But what should be Unsuppressed in the above example? A, B, or the type of A? The answer probably varies from implementation to implementation, and there is little value in defining it more tightly.
We do want to allow implementations to support pragma Unsuppress with an On parameter if they support pragma Suppress with an On parameter. This requires a specific permission, as implementations are not allowed to extend language-defined pragmas.
A benefit to making On parameters obsolescent is that this also signals implementors to spend little or no effort in this area, and users to not expect vendor effort in this area.
Implementations should not produce warnings for usages of pragma Unsuppress which have no effect. (This is varies from common practice for other pragmas.) It is not an error to use a pragma Unsuppress where nothing is suppressed. Such a usage may very well be a "preventative" pragma, inserted to insure that checks are made in a unit that requires checks.
Alternative names and definitions were considered for this pragma. These were ultimately rejected in order to standardize current practice, and to simplify the presentation. Some of these are discussed in the Appendix.
!corrigendum 11.5(1)
Replace the paragraph:
A pragma Suppress gives permission to an implementation to omit certain language-defined checks.
by:
Checking pragmas
give an implementation instructions on handling language-defined checks. A pragma Suppress gives permission to an implementation to omit certain language-defined checks, while a pragma Unsuppress revokes the permission to omit checks.
!corrigendum 11.5(3)
Replace the paragraph:
The form of a pragma Suppress is as follows:
by:
The forms of checking pragmas are as follows:
!corrigendum 11.5(4)
Replace the paragraph:
pragma Suppress(identifier [, [On =>] name]);
by:
pragma Suppress(identifier);
pragma Unsuppress(identifier);
!corrigendum 11.5(5)
Replace the paragraph:
A pragma Suppress is allowed only immediately within a declarative_part, immediately within a package_specification, or as a configuration pragma.
by:
A checking pragma is allowed only immediately within a declarative_part, immediately within a package_specification, or as a configuration pragma.
!corrigendum 11.5(6)
Replace the paragraph:
The identifier shall be the name of a check. The name (if present) shall statically denote some entity.
by:
The identifier shall be the name of a check.
!corrigendum 11.5(7)
Delete the paragraph:
For a pragma Suppress that is immediately within a package_specification and includes a name, the name shall denote an entity (or several overloaded subprograms) declared immediately within the package_specification.
!corrigendum 11.5(8)
Replace the paragraph:
A pragma Suppress gives permission to an implementation to omit the named check from the place of the pragma to the end of the innermost enclosing declarative region, or, if the pragma is given in a package_specification and includes a name, to the end of the scope of the named entity. If the pragma includes a name, the permission applies only to checks performed on the named entity, or, for a subtype, on objects and values of its type. Otherwise, the permission applies to all entities. If permission has been given to suppress a given check, the check is said to be suppressed.
by:
A checking pragma applies to the named check in a specific region (see below), and applies to all entities in that region. A checking pragma given in a declarative_part or immediately within a package_specification applies from the place of the pragma to the end of the innermost enclosing declarative region. The region for a checking pragma given as a configuration pragma is the declarative region for the entire compilation unit to which it applies.
If a checking pragma applies to a generic instantiation, then the checking pragma also applies to the instance. If a checking pragma applies to a call to a subprogram that has a pragma Inline applied to it, then the checking pragma also applies to the inlined subprogram body.
A pragma Suppress gives permission to an implementation to omit the named check (or every check in the case of All_Checks) for any entities to which it applies. If permission has been given to suppress a given check, the check is said to be suppressed.
A pragma Unsuppress revokes the permission to omit the named check (or every check in the case of All_Checks) given by any pragma Suppress that applies at the point of the pragma Unsuppress. The permission is revoked for the region to which the pragma Unsuppress applies. If there is no such permission at the point of a pragma Unsuppress, then the pragma has no effect. A later pragma Suppress can renew the permission.
!corrigendum 11.5(27)
Replace the paragraph:
An implementation is allowed to place restrictions on Suppress pragmas. An implementation is allowed to add additional check names, with implementation-defined semantics. When Overflow_Check has been suppressed, an implementation may also suppress an unspecified subset of the Range_Checks.
by:
An implementation is allowed to place restrictions on checking pragmas, subject only to the requirement that pragma Unsuppress shall allow any check names supported by pragma Suppress. An implementation is allowed to add additional check names, with implementation-defined semantics. When Overflow_Check has been suppressed, an implementation may also suppress an unspecified subset of the Range_Checks.
An implementation may support an additional parameter on pragma Unsuppress similar to the one allowed for pragma Suppress (see J.10). The meaning of such a parameter is implementation-defined.
!corrigendum 11.5(29)
Insert after the paragraph:
2 There is no guarantee that a suppressed check is actually removed; hence a pragma Suppress should be used only for efficiency reasons.
the new paragraph:
3 It is possible to give both a pragma Suppress and Unsuppress for the same check immediately within the same declarative_part. In that case, the last pragma given determines whether or not the check is suppressed. Similarly, it is possible to resuppress a check which has been unsuppressed by giving a pragma Suppress in an inner declarative region.
!corrigendum J.10(01)
Insert new clause:
Pragma
Suppress can be used to suppress checks on specific entities.
Syntax
The form of a specific Suppress pragma is as follows:
pragma Suppress(identifier, [On =>] name);
Legality Rules
The identifier shall be the name of a check (see 11.5). The name shall statically denote some entity.
For a specific Suppress pragma that is immediately within a package_specification, the name shall denote an entity (or several overloaded subprograms) declared immediately within the package_specification.
Static Semantics
A specific Suppress pragma applies to the named check from the place of the pragma to the end of the innermost enclosing declarative region, or, if the pragma is given in a package_specification, to the end of the scope of the named entity. The pragma applies only to the named entity, or, for a subtype, on objects and values of its type. A specific Suppress pragma suppresses the named check for any entities to which it applies (see 11.5). Which checks are associated with a specific entity is not defined by this standard.
Implementation Permissions
An implementation is allowed to place restrictions on specific Suppress pragmas.
NOTES
3 An implementation may support an entity parameter on pragma Unsuppress (see 11.5).
!ACATS Tests
ACATS C-tests should be created to check that checks are performed in a nested scope containing Unsuppress. (Most of this is not testable, unfortunately.)
!appendix

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

From: Randy Brukardt
Sent: Friday, November 19, 1999 7:34 PM

I've created this AI based on the discussion at the last ARG meeting.

I made one major change: based on the problem statement, the name "Unsuppress"
is the wrong name. In its intended use, we do not necessarily know that a
pragma Suppress has been applied to a region. Therefore, I renamed the pragma
to the more meaningful name "Require". I expect to catch some flak for this.

I find the preventative use of Require quite important, and quite in keeping
with the philosophy of Ada (make sure problems don't happen in the first
place).

It seems wrong to use a hypothetical pragma Unsuppress as a preventative: it
isn't undoing anything! Indeed, Ada users could imagine that it isn't allowed
unless there is a Suppress pragma to undo, and in that case, they would not
use it as a preventative.

I wonder if this entire clause shouldn't be renamed; it now is more about
controlling checks than about suppressing them.

One interesting issue: should pragma Require be allowed as a configuration
pragma? I have left it in, as that would allow effectively preventing the
adding of any pragma Suppresses to a program. That might be useful to some
paranoid organization. It also takes more words to disallow it than to allow
it.

Another interesting issue: should we allow "resuppression" of checks? I don't
feel strongly either way, but selected the current write-up because it was
more natural for pragma Require. The only way I see to support "resuppression"
is to write paragraph 8 in terms of "revoking the permission" to suppress
checks, which would complicate the description and would fit a pragma named
Unsuppress much better. It would also mean that a pragma Require would be
meaningless as a configuration pragma, as it would have no effect.

Having the pragma have no effect in some circumstances might be a impediment
to using it as a preventive, as a naive implementation of Ada might spew out
a warning everytime such a pragma occurs. I don't think we can say "don't warn
about this" in the reference manual, but without some guidance in this area,
I can see implementors going through the RM and implementing each pragma in
the "obvious" way [Janus/Ada, for instance, warns on any pragma that has no
effect], which would be the wrong thing to do in this case.

                        Randy.

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

From: Robert Dewar
Sent: Monday, November 22, 1999 1:58 PM

This is as far as I can tell exactly the same semantics as pragma
Unsuppress in GNAT, and indeed these are the obvious semantics,
since they derive directly from Suppress.

I see no point whatsoever in changing the name

a) People are used to pragma Unsuppress and are using it now

b) the name is FAR more obvious, Require?? Require what? Sure you could
make the same question for Suppress, but we know suppress already.

I would strongly oppose changing the name, and most certainly we will not
implement it under the name Require in GNAT, because this would be unnecessary
duplication.

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

From: Randy Brukardt
Sent: Monday, November 22, 1999 7:16 PM

> This is as far as I can tell exactly the same semantics as pragma
> Unsuppress in GNAT, and indeed these are the obvious semantics,
> since they derive directly from Suppress.

No, not exactly. The GNAT documentation that Ed handed out says "If there is no
corresponding pragma Suppress in effect, it [Unsuppress] has no effect." The
natural (to me) wording changes ended up with slightly different semantics, that
is that Suppress has no effect in a region where Require is given. The
difference is that Require can be given first -- it essentially is which is
given precedence.

> I see no point whatsoever in changing the name
>
> a) People are used to pragma Unsuppress and are using it now
>
> b) the name is FAR more obvious, Require?? Require what? Sure you could
> make the same question for Suppress, but we know suppress already.

Require the argument, just like Suppress is "Suppress the argument". I.e.

     pragma Require (Overflow_Check);

> I would strongly oppose changing the name.

OK, fair enough. In that case, I think that the answers to the two questions I
posed (does the pragma have an effect if no Suppress has been given, and should
"resuppression" be supported) should be different. And the pragma then has no
use as a preventative measure (both because it makes no sense to "Unsuppress" if
nothing is "Suppress"ed, and because a normally correct implementation of Ada 95
will complain about such pragmas).

> and most certainly we will not implement it under the name Require in GNAT,
> because this would be unnecessary duplication.

Well, this sounds very much like a Jean Ishbiah temper-tantrum: "If I can't have
my way, I'm going to take my ball and go home." I don't think this attitude is a
way to get useful work done (or to sway technical differences of opinion,
either). In any case, GNAT /= Ada. We want new features in Ada to be as useful
as possible to all users of Ada, not just to the customers of one particular
compiler.

                        Randy.

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

From: Robert Dewar
Sent: Monday, November 22, 1999 9:40 PM

<<No, not exactly. The GNAT documentation that Ed handed out says "If there is
no corresponding pragma Suppress in effect, it [Unsuppress] has no effect."
The natural (to me) wording changes ended up with slightly different semantics,
that is that Suppress has no effect in a region where Require is given. The
difference is that Require can be given first -- it essentially is which is
given precedence.>>

I think this is a bad choice, I prefer everything to nest, so that you
can nest Suppress/Unsuppress to any depth, and the innermost one is
what has the effect. This is the way GNAT works.

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

From: Robert Dewar
Sent: Monday, November 22, 1999 9:41 PM

incidentally, although I would argue for the more natural semantics that
Suppress can undo Unsuppress and vice versa to any depth, I don't really
care. It is obviously more work to implement Randy's suggested semantics,
but in practice it is completely unimportant, the probability of ever
having more than one level of these pragmas is zero in any case.

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

From: Randy Brukardt
Sent: Monday, November 22, 1999 10:12 PM

I agree that it doesn't matter much (the AI says as much).

I'm surprised that you say it would "obviously" take more work. I can see it
taking the same amount of work, but I don't see how it could take more. Indeed,
I would think it could take less work, because a stack isn't necessary to handle
it.

If others think it would take more work in their compilers, I'll junk the whole
AI and start over (the wording and discussion would have to be totally rewritten
to use a stacking semantics).

                                Randy.

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

From: John Barnes
Sent: Tuesday, November 23, 1999 4:37 AM

I don't  like the word Require either. It's a perfectly good word that
might be useful elsewhere whereas Unsuppress is a nasty word that is
most unlikely to be confused with anything else.

I would like to feel that the words have some symmetry.

John

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

From: Stephen Michell
Sent: Tuesday, November 23, 1999 7:19 AM

John Barnes wrote:

> I don't like the word Require either. It's a perfectly good word that
> might be useful elsewhere whereas Unsuppress is a nasty word that is
> most unlikely to be confused with anything else.
>

An excellent point. Then Ada could be the language with the nastiest keywords
in town. No one would DARE critisize us then (at least - not to our faces).

> I would like to feel that the words have some symmetry.
>

It does seem clear that "unsuppress" is now in current usage and in the
lexicon of the community, so that is the way it must remain. It is also clear
to me that one can never permanently override the effects of the other, once
it has been selected.

It may be reasonable, however, to create a pragma "require" that is a
configuration pragma. Such a pragma couldn't override pragma suppress in code,
it would just fail the compile. That could be a useful way of ensuring that
there are no checks suppressed in your 5 million line program.

  ...stephen

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

From: Robert Dewar
Sent: Tuesday, November 23, 1999 8:28 AM

Obviously the non-nesting semantics would take more work in GNAT, since it
is already done using stacking semantics. That was what I meant. We
implemented the stacking semantics because it seems clearly preferable.

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

From: Robert Dewar
Sent: Tuesday, November 23, 1999 8:27 AM

I find a stacking semantics far more natural here, and in fact the more
I think about it, the more I think your non-stacking semantics is
fundamentally flawed.

If I write a little section of code which depends on correctness on the
fact that checks are suppressed, say for performance reasons in the
context of a particular compiler, it should not be possible to destroy
the correctness of this code by nesting it within a construct that contains
an Unsuppress and knows nothing about the code nested within it.

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

From: Robert Dewar
Sent: Tuesday, November 23, 1999 8:38 AM

One more point on stacking semantics

It seems clear to me that Suppress and Unsuppress should be symmetrical
in their semantics. Anything else would be a surprise.

Given that it seems clear that a higher level Suppress cannot mask a lower
level Unsuppress, indeed in some sense that's the whole point of Unsuppress
(to undo a higher level Suppress).

So it would indeed seem odd if a Suppress cannot undo the effect of a higher
level Unsuppress.

I think part of the problem here is that Randy may have been trying to solve
a problem that Unsuppress is definitely NOT intended to address, and one
which to me is a non-problem, namely trying to ensure that checks are not
suppressed anywhere in your program.

Why do I think that is a non-problem? Simply because I have never run into
a customer requirement or an internal requirement for such a feature.

Unsuppress was put there solely for local control in situations which need
local control. Thus the stacking semantics seems much more natural to me.

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

From: Robert Dewar
Sent: Tuesday, November 23, 1999 8:18 AM

<<It may be reasonable, however, to create a pragma "require" that is a
configuration pragma. Such a pragma couldn't override pragma suppress in code,
it would just fail the compile. That could be a useful way of ensuring that
there are no checks suppressed in your 5 million line program.
>>

This seems overkill to me, I am really not aware of any requirements here.
After all Ada is full of deliberate loopholes to get around "checks",
most notably unchecked conversion and address clauses, why get all
upset about some local use of Suppress?

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

From: Stephen Michell
Sent: Tuesday, November 23, 1999 11:33 AM

  Sure, and the first thing that real projects do is write coding standards that
break peoples' fingers if they dare use one of those. Just ask me - I came back
Sunday from a week in the UK where those were some of the project's major
topics, and some people walked away with bandaged fingers :). Incidently, this
project does extremely heavy numeric calculations, numerical integrations of
transcendental functions, we do not suppress any checks, and performance is not
an issue.

The point is that Ada's loopholes are a real problem for real projects. We have
to do a lot of work to make sure that they are not used. Sure one can build
external tools to check for such things, but then one could code on C and rely
on external tools - right? Our community believes that the compilation
environment is the best line of defence for these issue, so let's seriously
consider ones that provide a real benefit.

A thought - The Annex H "pragma Restrictions" is helpful for many of the
significant issues, such as No_Allocation, No_Unchecked_Conversion, but
"no_pragma_suppress" is not one of the restrictions. Maybe that is the solution.

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

From: Randy Brukardt
Sent: Tuesday, November 23, 1999 2:02 PM

> I find a stacking semantics far more natural here, and in fact the
> more I think about it, the more I think your non-stacking semantics
> is fundamentally flawed.
>
> If I write a little section of code which depends on correctness on
> the fact that checks are suppressed, say for performance reasons in
> the context of a particular compiler, it should not be possible to
> destroy the correctness of this code by nesting it within a construct
> that contains an Unsuppress and knows nothing about the code nested
> within it.

I find this a pretty compelling argument in practice (even though a
"correct" program can't depend on Suppress). I couldn't think of a case
where it would matter when I wrote the AI.

I've thought about it some more, and while the "stacking" semantics is easy to
describe informally, a formal description seems difficult. I don't think that
any of the existing Ada pragmas work this way (can anyone think of a
counter-example)? Any suggestions of how to word this? All I can think of is
"revoking the permission to suppress checks", but that is a double negative.

I'll rewrite the AI and repost it sometime after Thanksgiving.

                                Randy.

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

From: Randy Brukardt
Sent: Tuesday, November 23, 1999 2:45 PM

> I think part of the problem here is that Randy may have been trying to solve
> a problem that Unsuppress is definitely NOT intended to address, and one
> which to me is a non-problem, namely trying to ensure that checks are not
> suppressed anywhere in your program.

Well, actually, I was trying to provide a way to insure (typically in a local
section of code) that checking *is* done. That's because the person who writes
the code is lot more likely to know the requirements of the code. That has to
work no matter what configuration pragmas, compiler options, or whatever happen.
"Unsuppress" seems to be the wrong name for this purpose, because it does not
necessarily have anything to do with a Suppress. (I can live with it though).

The non-stacking part came from two issues: the difficulty of writing wording to
explain stacking formally, and to give meaning to the pragma when given as a
configuration pragma. (Remember that Suppress can be a configuration pragma).
The GNAT Unsuppress appears to be always ignored when given as a configuration
pragma. I'm not very excited about requiring compilers to implement a pragma
that will always be ignored.

An interesting question: if both a Suppress and Unsuppress are given in the same
scope, what happens? Does the order matter. For instance,

       procedure ...
           pragma Suppress (All_Checks);
           pragma Unsuppress (Storage_Check);

Does this Suppress all checks except Storage_Check?

       procedure ...
           pragma Unsuppress (Storage_Check);
           pragma Suppress (All_Checks);

Does this Suppress all checks including Storage_Check?

The problem is that configuration pragmas really don't have an order, so we
can't tell which came first. If the meaning depends in the order that they're
seen in, then using both Suppress and Unsuppress as configuration pragmas is
implementation-dependent. Ugh.

                        Randy.

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

From: Jean-Pierre Rosen
Sent: Wednesday, November 24, 1999 1:44 AM

> I've thought about it some more, and while the "stacking" semantics is easy
> to describe informally, a formal description seems difficult. I don't think
> that any of the existing Ada pragmas work this way (can anyone think of a
> counter-example)? Any suggestions of how to word this? All I can think of is
> "revoking the permission to suppress checks", but that is a double negative.
>
What's the problem ? The pragma applies to the declarative region where it
appears. In the case of nesting, the innermost wins.
Just state that you cannot have a suppress and an unsuppress in the same
declarative region for the same check (on the same object).
This is the natural Ada semantics.

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

From: Robert I. Eachus
Sent: Friday, November 26, 1999 4:24 PM

I personally would find a non-stacking version of Unsuppress to be a problem,
even if it is never used in a stacking situation.  This is for code verification
reasons.  With the GNAT version, you just have to look at the closest nested
pragma, and if it matters to the logic of the code, the author will located it
as close as possible to the affected code to make verification easy.

Also, in the case of generics and in-line code, the fact that the code depended
on exceptions would need to be made visible to the user.

                                        Robert I. Eachus

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

From: Robert Dewar
Sent: Monday, November 29, 1999 5:09 AM

<<In the case of nesting, the innermost wins.
Just state that you cannot have a suppress and an unsuppress in the same
declarative region for the same check (on the same object).
This is the natural Ada semantics.
>>

We don't have any such restriction in GNAT, and

a) I see no reason for such a restriction, the semantics is natural, a
suppress cancels a previous unsuppress and vice versa.

b) This is used in practice sometimes to just unsuppress checks for an
individual statement or suppress them for an individual statement. Yes
you could declare a block for this, but why require this.

It would require extra mechanism to enforce such a restriction, since
it would mean that you not only have to have a flag indicating the
restriction, but also another flag indicating whether it was explicitly
set in the current scope.

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

From: Randy Brukardt
Sent: Monday, November 29, 1999 9:55 AM

>Jean-Pierre says:

> What's the problem ? The pragma applies to the declarative region where it
> appears.

How do you describe what Unsuppress does??? In this semantics, it doesn't do
anything by itself. It can only be described in terms of some (outer?) Suppress;
which leads to the double negative wording.

> In the case of nesting, the innermost wins.
> Just state that you cannot have a suppress and an unsuppress in the same
> declarative region for the same check (on the same object).

Given that the language-defined checks include some that overlap (the obvious
one is All_Checks and everything else), this could be quite difficult to do.

> This is the natural Ada semantics.

Yes, if you make that restriction. But the restriction isn't natural, and it
isn't easy to describe.

---

>Robert Dewar says:

>We don't have any such restriction in GNAT, and

>a) I see no reason for such a restriction, the semantics is natural, a
>suppress cancels a previous unsuppress and vice versa.

I agree, except that the "order" of the pragmas is not well-defined when they
are used as configuration pragmas. We could prevent the use of Unsuppress as a
configuration pragma, but this seems like an unnatural restriction.

>b) This is used in practice sometimes to just unsuppress checks for an
>individual statement or suppress them for an individual statement. Yes
>you could declare a block for this, but why require this.

Something is wrong with this. By 11.5(5), Suppress (and presumably Unsuppress) is
only allowed in a declarative_part, package specification, or as a configuration
pragma. That makes it impossible to use "around a statement" without an
enclosing block.

>It would require extra mechanism to enforce such a restriction, since
>it would mean that you not only have to have a flag indicating the
>restriction, but also another flag indicating whether it was explicitly
>set in the current scope.

Right. Plus you would have to deal with overlapping checks like All_Checks.

But without the restriction, it takes a lot more words to describe what happens.
This appears to be a case of "we know what we want, but we don't know how to
describe it".

                        Randy.

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

From: Tucker Taft
Sent: Monday, November 29, 1999 10:48 AM

Randy mentioned some concern about Unsuppress used as a configuration
pragma, as it seemed useless with the "stacking" interpretation.
However, if we consider a command-line parameter as the "outermost"
level, then a library-wide configuration pragma, then a compilation-wide
configuration pragma, then a scope-specific pragma, it seems like
configuration pragmas would fit into the "stacking" hierarchy in
a reasonable way.

For example, if you gave a "suppress-all" on the command line, but
had an Unsuppress for tag check in a library-wide configuration pragma,
that would seem meaningful and perhaps useful.

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

From: Robert Dewar
Sent: Monday, November 29, 1999 9:12 PM

I definitely agree, we have seen this standard and useful application of
Unsuppress used, and use it ourselves sometimes.

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

From: Randy Brukardt
Sent: Monday, November 29, 1999 1:31 PM

Tucker says:

> For example, if you gave a "suppress-all" on the command line, but
> had an Unsuppress for tag check in a library-wide
> configuration pragma, that would seem meaningful and perhaps useful.

Yes, but the problem is that it has been suggested that the order that
Suppress and Unsuppress pragmas is significant. That is,

   pragma Suppress (All_Checks);
   pragma UnSuppress (Overflow_Check);

(which suppresses all but Overflow_Check) means something different than

   pragma UnSuppress (Overflow_Check);
   pragma Suppress (All_Checks);

(which suppresses all checks), the UnSuppress being ignored.

The problem is that configuration pragmas are not given in a clearly defined
order. Since they can be compiled separately, and compilation order is not an
Ada 95 concept, the pragmas could occur in either order or simultaneously.
Similarly, we cannot say that compiler options occur before or after "real"
configuration pragmas. So how do we determine which of these are meant?

This means that the definition of configuration pragmas cannot depend on the
order of appearance. Yet, I've been told to write wording for UnSuppress which
*does* depend on the order that the pragmas appear. So, we have a problem.

If we get rid of the significance of the order (at least within a single scope),
we get rid of the problem, but that the cost of complicating things (and I
suspect that Robert won't go along with any such semantics). [That is, in a
scope, UnSuppress has precedence over Suppress.] We could also prevent multiple
pragmas in the same scope, but that is a problem because of overlapping sets of
checks. Or we could simply eliminate UnSuppress as a configuration pragma, which
would prevent the problem from occurring. None of these look like particularly
good choices.

                        Randy.

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

From: Robert A Duff
Sent: Monday, November 29, 1999 4:03 PM

> The problem is that configuration pragmas are not given in a clearly defined
> order.

Have you considered making it implementation defined in that case?

- Bob

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

From: Robert Dewar
Sent: Monday, November 29, 1999 9:45 PM

<<Have you considered making it implementation defined in that case?
>>

Sounds reasonable to me, it depends on which is processed last, which
is indeed impl defined.

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

From: Randy Brukardt
Sent: Monday, November 29, 1999 6:48 PM

Not seriously. That seems like a last resort: punt! Such a definition would
not be useful to people who need portable code, and of course would be
untestable.

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

From: Robert Dewar
Sent: Monday, November 29, 1999 10:16 PM

Don't dance on pin heads :-)

Who cares if there are multiple conflicting pragmas in the configuration
pragmas, this simply won't happen in practice. Don't undermiune the
utility of USEFUL applications by worrying about things that are useless!

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

From: Randy Brukardt
Sent: Tuesday, November 30, 1999 11:10 AM

I would agree, except that multiple conflicting pragmas are USEFUL: they provide
an easy way to turn off all but one check:

    pragma Suppress (All_Checks);
    pragma Unsuppress (Storage_Check);

(But of course the order is significant). This is what I use in release code
where size is an issue: the only check that I find critical is Stack and Heap
checking (because the results are so catastrophic if they are omitted).

I want to have a way to do this as a configuration pragma/option in any
implementation that I'm using. Making it implementation-defined eliminates that
possibility (unless all of the vendors support it in the same way, which is very
unlikely).

                	Randy.

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

From: Tucker Taft
Sent: Tuesday, November 30, 1999 3:59 PM

Randy Brukardt wrote:
>
> > > The problem is that configuration pragmas are not given in a clearly defined
> > > order.
> >
> > Have you considered making it implementation defined in that case?
>
> Not seriously. That seems like a last resort: punt! Such a definition would
> not be useful to people who need portable code, and of course would be
> untestable.

I would make it well defined if the configuration pragmas are all
in the same file (i.e., the last one applies).  If the
configuration pragmas are in separate files, then it is implementation-defined
what order these end up in when conceptually combined.  They
will be combined in some order, so there are a finite number of
distinct orders possible, and so it is testable.

If a programmer wants portability, they would put all the
configuration pragmas in the same file.

Hence, if they wanted to suppress everything but tag_check, they
could write:

    pragma Suppress(All_Checks);
    pragma Unsuppress(Tag_Check);

That seems pretty intuitive.

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

From: Ted Baker
Sent: Tuesday, November 30, 1999 7:07 PM

After hearing a lot of talk on this one, I believe that as a user I would
view the nesting of Suppress and Unsuppress pragmas as unwise,
and so would  prefer for an implementation to at least give a
warning when this occurs.

However, if nesting is allowed, the innermost nested region should
certainly retain the effect of the pragma given for that region.

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

From: Robert Dewar [dewar@GNAT.COM]
Sent: Tuesday, November 30, 1999 7:30 PM

YOu don't want a warning for all cases of nesting, otherwise every use
of Unsuppress in a typically suppressed region would generate a warning.
Since this kind of use is the principle utility o Unsuppress, it seems
wrong to warn unconditionally.

For example, we generally compile the GNAT runtim elibrary with checks off
(i.e. the equivalent of a pragma Suppress at the configuration level).

Individual little sections of the runtime that rely on checks (e.g. converting
Constraint_Error into Time_Error in Calendar) do an Unsuppress.

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

From: Robert Dewar
Sent: Tuesday, November 30, 1999 5:40 PM

<<I would make it well defined if the configuration pragmas are all
in the same file (i.e., the last one applies).  If the
configuration pragmas are in separate files, then it is implementation-defined
what order these end up in when conceptually combined.  They
will be combined in some order, so there are a finite number of
distinct orders possible, and so it is testable.
>>

I agree with this, and cannot imagine that it in fact does not hold already
for all existing compilers.

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

From: Tucker Taft
Sent: Thursday, December 02, 1999 10:23 AM

Randy Brukardt wrote:
> I would agree, except that multiple conflicting pragmas are USEFUL: they
> provide an easy way to turn off all but one check:
>
>     pragma Suppress (All_Checks);
>     pragma Unsuppress (Storage_Check);
>
> (But of course the order is significant). This is what I use in release code
> where size is an issue: the only check that I find critical is Stack and
> Heap checking (because the results are so catastrophic if they are omitted).
>
> I want to have a way to do this as a configuration pragma/option in any
> implementation that I'm using. Making it implementation-defined eliminates
> that possibility (unless all of the vendors support it in the same way,
> which is very unlikely).

I trust you received the earlier message where this would be well-defined
if they are all in the same compilation.  If the configuration pragmas
are in separate (unit-less) compilations, then the order in which the
configuration pragmas are combined is implementation-defined (or perhaps
even "unspecified").  That would seem to address your concern.
In general, having multiple unit-less compilations with configuration
pragmas is a bit confusing anyway, I would say (though our front end
supports it ;-).

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

From: Tucker Taft
Sent: Monday, December 13, 1999 2:38 PM

Randy Brukardt wrote:
>
> Here is a complete rewrite of this AI. I don't much like the wording, but I
> think it is correct (if a bit subtle).

Looks good.  I noticed one typo (see below).

One typo:

>
> ...
> Checking pragmas give an implementation instructions on handling
> language-defined checks. A pragma Suppress gives permission to an
> implementation
> to omit certain language-defined checks, while a pragma Unsuppress revokes
> the
> permission to make omit checks.
                XXXX

> ...

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

From: Jean-Pierre Rosen
Sent: Tuesday, December 14, 1999 12:38 PM

> Here is a complete rewrite of this AI. I don't much like the wording, but
I
> think it is correct (if a bit subtle).
>
[...]
> Consider, for instance, an integer saturation arithmetic package. The
> multiply
> operation might look like:
>
>      function "*" (Left, Right : Saturation_Type) return Saturation_Type
is
>      begin
>          return Integer(Left) * Integer(Right);
>      exception
>          when Constraint_Error =>
>              return Saturation_Type'Last;
>      end "*";
>
> This function will not work properly without overflow checking. Ada 95
does
> not provide a way to indicate this to the compiler and programmers.
>
[...]
> Pragma Unsuppress revokes the permission to suppress a check, that is, it
> means
> that the given check must be performed.
>
Given the example and the wording, I am afraid that it may be interpreted to
mean that if, for example, Float'Machine_Overflows is False, the check be
performed anyway. I'm pretty sure it is not the intent, but maybe some
additionnal wording could be added for this.

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

From: Randy Brukardt
Sent: Tuesday, December 14, 1999 4:48 PM

I specifically selected an Integer example to avoid any question of whether the
check has to be performed in the normal case. Also, the wording you are
objecting to is used only in the informal description of the pragma. I used that
to make it clearer what is meant. The formal wording never says anything about a
check being required; it only talks about revoking the permission granted by a
Suppress pragma.

Obviously, I could add a paragraph in the discussion saying that Unsuppress
"obviously" doesn't add any requirements beyond those that would exist anyway
(in the absence of any checking pragmas), but this seems obvious enough. Would
anyone seriously think otherwise??

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

From: Robert I. Eachus
Sent: Friday, December 17, 1999 5:53 PM

At 04:48 PM 12/14/1999 -0600, Randy Brukardt wrote:
>Obviously, I could add a paragraph in the discussion saying that Unsuppress
>"obviously" doesn't add any requirements beyond those that would exist
>anyway (in the absence of any checking pragmas), but this seems obvious
>enough. Would anyone seriously think otherwise??

    Why not just change the sentence:

> A pragma Unsuppress revokes the permission to omit the named check for any
> entities to which it applies.

    To:

> A pragma Unsuppress revokes any permissions given by pragma Suppress to omit
> the named check for any entities to which it applies.

    Or if this is still too verbose, you could go with:

> A pragma Unsuppress revokes such permissions to omit the named check for any
> entities to which it applies.

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

From: Randy Brukardt
Sent: Thursday, December 23, 1999 1:44 PM

You're changing the actual (RM-style) wording, while Jean-Pierre was objecting
to the wording of the example (at least, that's how it appeared to me).

I don't see any reason to add the redundancy to the RM wording, because such
things tend to get us in trouble down the road. There aren't any other
permissions to omit checks in the RM (and implementation-defined permissions
aren't our business). There are cases where the RM says that the checks don't
have to be made, but these aren't permissions. For instance, the
Machine_Overflows=False case seems justified by 4.5(10), which simply says that
checks are made if Annex G is supported, and saying nothing further.

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

From: Tucker Taft
Sent: Friday, March 10, 2000 4:50 PM

We have recently been implementing pragma unsuppress.
As usual, we have found some subtleties that were not
anticipated when we all glibly agreed that "of course the
innermost one applies" when there is more than one pragma
applicable.

Here are some nasty cases:

    pragma Suppress(Access_Check, On => Some_Type);
    pragma Unsuppress(Access_Check);

Which one applies?  The Unsuppress comes later, but it is less
specific.  Our conclusion:  a Suppress...On can only be overridden
by an inner/later Unsuppress...On.  A non-specific Unsuppress does not
override a Suppress...On.  Similarly, an Unsuppress...On will always
override a non-specific Suppress, independent of which is innermost.

Here is another:

  in one file:

    package P is
       pragma Suppress(Access_Check);

       ...
    end P;

  ------------
  in a separate file:

    pragma Unsuppress(Access_Check);

    package body P is
       ...
    end P;

Is Access_Check unsuppressed inside the body of P?
--------
In other words, a declarative-region-wide suppress is given
in a package spec, and then a source-wide configuration pragma
unsuppress is given in the file where the body appears.
Which applies?

This brings up a more general question which is an issue even without
adding "unsuppress" to the mix.  If a package spec is compiled in
a source file where a source-wide configuration pragma suppress appears,
does that pragma apply to the body of the package, even though the
body is in a separate file?  Similar question for a stub and a subunit...
In other words, at the end of a package spec, should one take a
snapshot of the suppression state, and reincarnate that state when
beginning the package body.  Corresponding question applies to
a stub/subunit.  When one does reincarnate that state, how is it affected
by any pragmas specified for the source file containing the body/subunit?

One possible approach:
  a) All [un]suppress pragmas applicable at the end of a spec/stub
     (including source-wide config pragmas) are "inherited" by the body/subunit.
 However..
  b) Any [un]suppress pragmas applicable at the point immediately
     enclosing a body/subunit (including source-wide config pragmas)
     are presumed to be "inner" to those inherited from the spec/stub.

I realize this approach does not match the visibility rules, where
the declarations inside a package spec hide homographic declarations
enclosing the package body.  However, for something like suppress,
it seems like physical enclosure should be more important than
state inherited from the spec/stub.

I could also be convinced otherwise, though I will admit that the above
approach has a relatively straightforward implementation, whereas other
approaches might require keeping a more complicated and burdensome
"suppression" state.

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

From: Robert Dewar
Sent: Friday, March 10, 2000 11:16 PM

<<Which one applies?  The Unsuppress comes later, but it is less
specific.  Our conclusion:  a Suppress...On can only be overridden
by an inner/later Unsuppress...On.  A non-specific Unsuppress does not
override a Suppress...On.  Similarly, an Unsuppress...On will always
override a non-specific Suppress, independent of which is innermost.
>>

Seems obviously correct to me :-)

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

From: Robert Dewar
Sent: Friday, March 10, 2000 11:17 PM

for me by the way, Tuck's notes on this are consistent with the way
things work now with suppress, a specific entity suppress always
supercedes the no-suppress general case.

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

From: Randy Brukardt
Sent: Monday, March 13, 2000 12:23 PM

Humm, seems like a total role reversal here: I wrote the wording for it, and
you're trying to implement it. I guess we'll both get to see the other side
now...

> Here are some nasty cases:
>
>     pragma Suppress(Access_Check, On => Some_Type);
>     pragma Unsuppress(Access_Check);
>
> Which one applies?  The Unsuppress comes later, but it is less
> specific.  Our conclusion:  a Suppress...On can only be overridden
> by an inner/later Unsuppress...On.  A non-specific Unsuppress does not
> override a Suppress...On.  Similarly, an Unsuppress...On will always
> override a non-specific Suppress, independent of which is innermost.

Well, I considered these cases when I wrote the text, and I am certain that the
wording covers them, but it does not get the result that you want.

I suppose it would be possible to rewrite the wording to define "specific" and
"non-specific" checking pragmas, and try to make some rules about what does and
does not override. It appears that the only special case that you want is that a
non-specific Unsuppress does not override a specific Suppress. Otherwise,
everything would work as defined in the AI. Is that correct?

I would be concerned about this change introducing anomalies. Once we deviate
from a strict stacking scheme, we're a lot more likely to get some strange
effects. For instance, does a Unsuppress...On override a Suppress...On for a
related entity?  (It is clear that the names given in the On=> may relate to
different aspects of the same entity.)  Consider:

        type Some_Type is access ....
        subtype Sub_Type is Some_Type <some constraint>;

        pragma Suppress (Access_Check, On => Sub_Type);
        pragma Unsuppress (Access_Check, On => Some_Type);
        -- Is the check on Sub_Type suppressed here?

I also wonder if this is a good idea. I don't think we really care what happens
with same-scope Suppress/Unsuppress as long as we can define it; what is
important that *inner* scope Unsuppress works as intended. The problem is that
the intended use of Unsuppress is to insure that checks are made in a subprogram
or block that depends on the raising of exceptions. A programmer needing that is
probably going to stick one or more non-specific Unsuppress pragmas into the
subprogram or block. They would be pretty surprised if the Unsuppress didn't
work because somewhere in the program there was an Suppress (On =>) on the type.

This reminds me why I think the Suppress (,On =>) is the tool of the devil.
Because it allows programmers to end-run Ada checking on some type, leaving a
situation where any definition of Unsuppress is going to cause trouble for some
users. In this case, I tend to lean toward making the canonical Ada semantics,
meaning that it is impossible to unsuppress too much.

> Here is another:
> --------
> In other words, a declarative-region-wide suppress is given
> in a package spec, and then a source-wide configuration pragma
> unsuppress is given in the file where the body appears.
> Which applies?

I think it has to be the Suppress, because it is in an inner scope. These things
aren't textual (I wish they were, but that's irrelevant).

> This brings up a more general question which is an issue even without
> adding "unsuppress" to the mix.  If a package spec is compiled in
> a source file where a source-wide configuration pragma suppress appears,
> does that pragma apply to the body of the package, even though the
> body is in a separate file?  Similar question for a stub and a subunit...
> In other words, at the end of a package spec, should one take a
> snapshot of the suppression state, and reincarnate that state when
> beginning the package body.  Corresponding question applies to
> a stub/subunit.  When one does reincarnate that state, how is it affected
> by any pragmas specified for the source file containing the
> body/subunit?

This seems to be a separate question worth considering irrespective of
Unsuppress. In that case, it ought to be handled in a separate AI, as
sticking important questions into amendment AIs that may never be approved
or adopted is a bad idea. Everyone, is this a "question worth answering"?

> One possible approach:
>   a) All [un]suppress pragmas applicable at the end of a spec/stub
>      (including source-wide config pragmas) are "inherited"
> by the body/subunit.
>  However..
>   b) Any [un]suppress pragmas applicable at the point immediately
>      enclosing a body/subunit (including source-wide config pragmas)
>      are presumed to be "inner" to those inherited from the spec/stub.
>
> I realize this approach does not match the visibility rules, where
> the declarations inside a package spec hide homographic declarations
> enclosing the package body.  However, for something like suppress,
> it seems like physical enclosure should be more important than
> state inherited from the spec/stub.
>
> I could also be convinced otherwise, though I will admit that the above
> approach has a relatively straightforward implementation, whereas other
> approaches might require keeping a more complicated and burdensome
> "suppression" state.

While I can sympathize with this approach, I wouldn't want to have to write
language wording to describe this. It would be necessary to exclude
environment-wide configuration pragmas from the "however" (otherwise, they would
"re-emerge" in the body after overriding them in the specification). That will
complicate the wording a lot.

Moreover, I wonder if this is what compilers are actually doing. I'm pretty sure
that Janus/Ada doesn't propagate pragma Suppress to the body or to stubs.

It could be very disruptive to users to force compilers to propagate Suppress to
a body or stubs if they don't currently do so. Any code that depended on the
raising of exceptions would suddenly start failing. It might also cover up bugs
(by eliminating checks that would have caught bugs).

Because of these issues, I think we need to consider any rule in this area
*very* carefully.

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

From: Robert Dewar
Sent: Monday, March 13, 2000 1:22 PM

One problem in general here is that while suppress has no semantics (since
it can be ignored), unsuppress DOES have semantics. That means that the
question unanswered in the RM:

What exact entities should be tested for suppress to see if this check
should be carried out?

Has to be answered for unsuppress if you are not careful, and that way
lies madness.

I think it is clear from both this definitional point of view, and from
an implementation point of view that an unsupress on a specific entity
should only have the effect of cancelling a previous suppress on that
specific entity.

Yes, it sounds useful to be able to do a general suppress, and then
unsuppress on a specific entity, but this is simply not viable in
practice, unless you want to leave things entirely implementation
dependent.

To see what I am talking about here consider


subtype r is integer range 1 .. 10;
subtype s is integer range 1 .. 20;

rv : r;
sv : s;

rv := sv;

Now what entities to we test for suppression:

rv
sv
integer
r
s
...

The RM really does not say clearly.

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

From: Randy Brukardt
Sent: Monday, March 13, 2000 5:37 PM

Robert wrote:

> One problem in general here is that while suppress has no semantics (since
> it can be ignored), unsuppress DOES have semantics. That means that the
> question unanswered in the RM:
>
> What exact entities should be tested for suppress to see if this check
> should be carried out?
>
> Has to be answered for unsuppress if you are not careful, and that way
> lies madness.


Thanks for pointing this out. This point brings a whole different perspective to
this discussion.

I agree with this point - that we have to avoid any semantics that requires
answering this question.

More from Robert:

> I think it is clear from both this definitional point of view, and from
> an implementation point of view that an unsuppress on a specific entity
> should only have the effect of canceling a previous suppress on that
> specific entity.
>
> Yes, it sounds useful to be able to do a general suppress, and then
> unsuppress on a specific entity, but this is simply not viable in
> practice, unless you want to leave things entirely implementation
> dependent.


To avoid that, we also have to avoid the following:

     pragma Suppress (Access_Check); -- A configuration pragma.

     pragma Suppress (Access_Check, On => Some_Type);
     ...
     pragma Unsuppress (Access_Check, On => Some_Type);

     -- Is Access_Check suppressed here on Some_Type?

If we expect Access_Check to be not suppressed on Some_Type here, we have the
same problem that Robert is concerned about. (That is, this is equivalent to a
specific Unsuppress on a non-specific Suppress.) So merely requiring that an
Unsuppress matches some Suppress pragma to have an effect is insufficient.

To avoid Robert's problem, we would have to define the semantics of Unsuppress
(at least specific Suppress) as cancellation of a specific pragma, and require
equivalence of the names in the On part. (We probably could use conformance for
this).

It appears to me that such a rule would have a complex implementation, because a
stack of pragmas would have to kept around (and be searchable) at all times.
Perhaps this is not a problem for other implementations - it would be for
Janus/Ada, but it also is irrelevant since Janus/Ada doesn't support the On
=>parameter anyway.

Another effect of this definition would be that it would be (nearly) impossible
to use Unsuppress as a general and portable preventative measure, as you would
have to give a non-specific one AND every possible specific one to insure a
particular check is made. To me, this means the important problem has not been
solved.

---

There is an alternative way out of this dilemma, although I think some people
won't like it: refuse to provide Unsuppress (xxx, On => ...) in the RM. This
would necessarily mean that general Unsuppress must undo specific Suppress (but
I believe this is necessary to solve both user problems).

Keep in mind that Unsuppress has two purposes. One is to provide a band-aid when
someone suppresses checks on a unit or program and something breaks. While this
band-aid use is important, it is not necessary for it to be well-defined in RM
terms. That is, the main issue when using Unsuppress to fix a problem is that it
undoes whatever is causing the problem, not that what exactly is happening is
well-defined. I think we can trust compiler-writers to do the right thing here.

On the other hand, using Unsuppress as a preventative absolutely must be
portable. Let me give a concrete example of what I mean by using Unsuppress as a
preventative.

We distribute the Claw bindings as source code. We do this so customers can
recompile it on a new version of a compiler, or on a different compiler, without
have to depend on us to support it for them. Clearly, this means that we have
limited control over the compiler options used when compiling the source. We
want to make the source code as bullet-proof as possible, because we don't want
to have to spend lots of technical support time tracking down problems. Thus, we
try to write the code as generically as possible, so that the choice of compiler
options does not affect the code.

If we had a piece of code where it is necessary to handle Ada exceptions, we
would want to be able to tell the compiler not to mess with it. A way to do that
with the proposal as defined in the AI would be to put a pragma Unsuppress
(Some_Check); into the code. The idea would be to prevent any compiler options
(or ham-handed maintenance programmer, for that matter) from causing a subtle
bug. For this use, it is critical that the meaning of Unsuppress be
well-defined. Moreover, for this use, it is important that Unsuppress override
ANYTHING Suppressed in an outer scope, not matter what the syntax of the
command.

It is the preventative use that is important to be well-defined and supported
the same way by all compilers. That means that it is the primary need for the
ARG to standardize and the ACAA to test. To the extent that this helps
standardize the band-aid use, all the better.

In order to better support the band-aid use, I would allow implementors to
support Unsuppress (xxx, On => ...) without trying to define exactly what it
means. This means leaving it Implementation-Defined, much as Robert noted we
would have to do.

So far as I can tell, there is no definitional problem with a non-specific
Unsuppress overriding specific ones, nor any implementation problem. (You have
to be able to back them out when the end of the scope of the Suppress is reached
anyway, so there must be some sort of list around.)

Thus, I am now convinced that the wording I proposed in the AI is correct,
except that we have to make the meaning of Unsuppress (xxx, On => ...)
implementation defined, at least in some cases. It certainly has to be
implementation-defined if there exists any Suppress pragmas which name an
overlapping check (such as All_Checks) and/or a non-conformant name which
denotes a related entity and/or are non-specific. I'm not sure it is worth the
effort to define the case where it does have to be *not* implementation defined:
(when the check and name of a single Suppress pragma conform), but I will leave
that to the rest of the ARG.

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

From: Erhard Ploedereder
Sent: Monday, March 13, 2000 7:33 PM

Let me throw in a suggestion. Why not simply define Unsuppress without
the On parameter? That way, all these nasty issues seem to be avoided.
Yes, it's not quite so convenient, expressive, etc, etc, but it seems
to avoid all the nastiness that you've been discussing.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 6:58 AM

<<To avoid that, we also have to avoid the following:

     pragma Suppress (Access_Check); -- A configuration pragma.

     pragma Suppress (Access_Check, On => Some_Type);
     ...
     pragma Unsuppress (Access_Check, On => Some_Type);

     -- Is Access_Check suppressed here on Some_Type?
>>

Since people are trying to copy a well established and frequently used
feature in GNAT, it may be useful to say what GNAT does :-)

The way GNAT works is that a check is suppressed if

EITHER it is scope suppressed OR (for some "appropriate" choice of entities
to test) it is suppressed on a relevant entity.

This means that the sequence above is well defined to suppress access checks
on Some_Type in GNAT. I am not necessarily saying that is the way things
should work, but this has a clear implementation model, and is also easy
to describe.

In other words, my suggestion is precisely, as in my previous message,
that a pragma Unsuppress has ONLY the effect of cancelling the effects
(whatever they migfht be) of a previous Suppress with the same entity.

Thus the sequence above is equivalent to just the first pragma, and so
the check is indeed suppressed.

In fact as I think about it, I would recommend that this in fact be the
defined semantics.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 7:12 AM

<<Let me throw in a suggestion. Why not simply define Unsuppress without
the On parameter? That way, all these nasty issues seem to be avoided.
Yes, it's not quite so convenient, expressive, etc, etc, but it seems
to avoid all the nastiness that you've been discussing.
>>

I could buy this approach.

I also think that my definition is viable. I will repeat it again.

pragma Unsuppress with an entity has ONLY the effect of cancelling a
previous Suppress applying to this same entity.

If there is no such previous Suppress, then the pragma Unsuppress has
no effect at all.

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

From: Tucker Taft
Sent: Tuesday, March 14, 2000 9:16 AM

This seems odd to me.  I would expect an Unsuppress...On to ensure
that (unless overridden by a Suppress...On) the specified check
would not be suppressed, even if there is a suppress-all somewhere
in scope.

But I also agree with Randy that we should try to find something
we can all agree on.

If we abandon the "Unsuppress...On" we will still need to define
how Unsuppress relates to Suppress...On.

Also, noone has addressed my concern about spec/body inheritance
and stub/subunit inheritance, as it relates to source-wide
configuration pragmas.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 9:30 AM

<<This seems odd to me.  I would expect an Unsuppress...On to ensure
that (unless overridden by a Suppress...On) the specified check
would not be suppressed, even if there is a suppress-all somewhere
in scope.
>>

I explained why this is inherently non-portable. Let me try again.

The RM has nothing to say, nothing at all, about WHICH entities are
involved for consideration when considering whether to remove a given
check.

This means that the set of possibly erroneous programs is not very
well defined, and is in fact implementation dependent. Trying to define
this more specifically would be a horrible nightmare in my opinion.
But in the case of Suppress it really does not matter, since if a given
suppress has no effect, that is really not critically important, and
programs should not rely on executing erroneous code (working correctly
is an acceptable behavior for erroneous code in this case).

But in the Unsuppress case, if you follow the semantics suggested by Tuck
above, it then becomes critically important to determine which entities
get tested (see my previous message for an example showing why this is
hard to do).

Yes, the above idea makes sense. No, it is not practical.

If people share Tuck's reaction that my suggestion is odd, then the best
remedy is to follow Erhard's idea and only allow pragma Unsuppress with
no Entity argument (GNAT will of course continue to implement the full
form, since we are not about to make incompatible changes here!)

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

From: Randy Brukardt
Sent: Tuesday, March 14, 2000 11:19 AM

Robert said:

> > I also think that my definition is viable. I will repeat it again
> >
> > pragma Unsuppress with an entity has ONLY the effect of canceling a
> > previous Suppress applying to this same entity.
> >
> > If there is no such previous Suppress, then the pragma Unsuppress has
> > no effect at all.

and Tucker replied:

> This seems odd to me.  I would expect an Unsuppress...On to ensure
> that (unless overridden by a Suppress...On) the specified check
> would not be suppressed, even if there is a suppress-all somewhere
> in scope.

I discussed this in detail last night. (So much detail that most everyone seems
to have glossed over it.) Robert's semantics are the only possible semantics
that can be defined in a fully-implementation independent fashion.

However, I objected to this semantics on a usage basis, as it makes it very
difficult to write a bullet-proof subprogram that depends on checks being made
(and exceptions raised).

Thus, I proposed only defining Unsuppress without the On parameter, and
including an implementation permission to allow implementations (such as GNAT)
to support Unsuppress with an On parameter with implementation-defined
semantics.

> If we abandon the "Unsuppress...On" we will still need to define
> how Unsuppress relates to Suppress...On.

The only way for it to be useful is if it revokes the permissions on all
Suppress...On. Otherwise, it can't be used to idiot-proof code that needs
checking, and that is the use that needs to be defined portably. (I gave a
concrete example of this last night.)

> Also, no one has addressed my concern about spec/body inheritance
> and stub/subunit inheritance, as it relates to source-wide
> configuration pragmas.

Not true. I commented on it originally, suggesting that we determine what
existing implementations do here. (And opening a separate AI on the topic if
people feel it is important enough, as it has little to do with Unsuppress.)
Forcing implementations to inherit Suppress in bodies would be very bad *if*
compilers aren't already doing it. I know Janus/Ada doesn't do it, but I don't
know what other compilers do (which is more important).

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

From: Ada Rapporteur Group of WG9; managing the Ada issues [ARG@ACM.ORG]
on behalf of Tucker Taft [stt@averstar.com]
Sent: Tuesday, March 14, 2000 10:39 AM
To: ARG@ACM.ORG
Subject: Re: AI 224 suppress/unsuppress details

Robert Dewar wrote:
>
> <<This seems odd to me.  I would expect an Unsuppress...On to ensure
> that (unless overridden by a Suppress...On) the specified check
> would not be suppressed, even if there is a suppress-all somewhere
> in scope.
> >>
>
> I explained why this is inherently non-portable. Let me try again.

I accept that it is harder to define the semantics.  By saying it is "odd"
I meant that it would be unintuitive and potentially misleading for the
user if Unsuppress...On did not in fact unsuppress a check.

Given that, and your argument that the semantics are difficult to define,
one could argue for discouraging the use of Unsuppress...On.  However,
if GNAT continues to support it, then does that mean we should all feel free
to support it in various non-portable ways?  My sense is that we should either
*all* drop support for it, or include it with specifically implementation-defined
semantics (perhaps deserving a warning?).

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

From: Tucker Taft
Sent: Tuesday, March 14, 2000 12:51 PM

Randy Brukardt wrote:
>
> Robert wrote:
>
> > One problem in general here is that while suppress has no semantics (since
> > it can be ignored), unsuppress DOES have semantics. That means that the
> > question unanswered in the RM:
> >
> > What exact entities should be tested for suppress to see if this check
> > should be carried out?
> >
> > Has to be answered for unsuppress if you are not careful, and that way
> > lies madness.
>
> Thanks for pointing this out. This point brings a whole different
> perspective to this discussion.
>
> I agree with this point - that we have to avoid any semantics that requires
> answering this question.

I don't agree with the distinction between Suppress...On and
Unsuppress...On as far as semantics (see below).

>
> More from Robert:
>
> > I think it is clear from both this definitional point of view, and from
> > an implementation point of view that an unsuppress on a specific entity
> > should only have the effect of canceling a previous suppress on that
> > specific entity.
> >
> > Yes, it sounds useful to be able to do a general suppress, and then
> > unsuppress on a specific entity, but this is simply not viable in
> > practice, unless you want to leave things entirely implementation
> > dependent.

I don't understand this logic either.  Should a specific Suppress...On
be able to override a non-specific Unsuppress?  If so, then the converse
should work as well, in my view.

> ...
> If we had a piece of code where it is necessary to handle Ada exceptions, we
> would want to be able to tell the compiler not to mess with it. A way to do
> that with the proposal as defined in the AI would be to put a pragma
> Unsuppress (Some_Check); into the code. The idea would be to prevent any
> compiler options (or ham-handed maintenance programmer, for that matter)
> from causing a subtle bug. For this use, it is critical that the meaning of
> Unsuppress be well-defined.

I don't see why Suppress...On need not be "well defined" whereas
Unsuppress...On does need to be.  Suppress...On is stating "I know
I never fail Blah_Check on blah object/subtype."  If this is misinterpreted
to apply to some other object/subtype, where Blah_Check failures do
occur and where exceptions should be raised, then this affects semantics
just as much as a misinterpreted Unsuppress...On.

I don't see any need to be more or less precise in Unsuppress...On than
in Suppress...On (the problems that can occur seem to be essentially
the same if the pragma is misinterpreted -- a check might get suppressed
that in fact would fail in the given program).

> ... I'm not sure it is worth
> the effort to define the case where it does have to be *not* implementation
> defined: (when the check and name of a single Suppress pragma conform), but
> I will leave that to the rest of the ARG.

I'm not sure why you talk about "conforming" here.  We are talking about
entities, not expressions, so either they denote the same entity, or
they don't.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 1:41 PM

<<I accept that it is harder to define the semantics.  By saying it is "odd"
I meant that it would be unintuitive and potentially misleading for the
user if
Unsuppress...On did not in fact unsuppress a check.
>>

No more unintuitive than doing a Suppress on a given entity and finding
out that it does not suppress the check. For example, in

  A := B;

where there is a tag check, GNAT checks the type involved, but not the
class type, or any parent type, or the objects A and B, and indeed one
customer recently was surprised that suppressing checks on A did not work.

<<Given that, and your argument that the semantics are difficult to define,
one could argue for discouraging the use of Unsuppress...On.  However,
if GNAT continues to support it, then does that mean we should all feel free to
support it in various non-portable ways?  My sense is that we should either
*all* drop support for it, or include it with specifically
implementation-defined semantics (perhaps deserving a warning?).
>>

Well I think it is a bit unrealistic to ask GNAT to unimplement anything.
Why should we cause our customers incompatibility problems. I would
certainly be willing to have this case included in the

pragma Restrictions (No_Implementation_Pragmas)

P.S. it would be nice to pseudo-standardize this restriction identifier

The only time that GNAT unimplemented anything in the name of conformity
was the handling of Call_By_Copy. This caused customers a LOT of problems,
and if we knew what we did now, we would not repeat that experience.

Yes, I know it is nice to be conformant, but I think this urge should be
restricted to defining a subset that everyone will implement, not agitation
to unimplement allowed extensions.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 1:59 PM

<<However, I objected to this semantics on a usage basis, as it makes it very
difficult to write a bullet-proof subprogram that depends on checks being
made (and exceptions raised).
>>

Now this must be wrong, *adding* a facility cannot make it harder to do
something!

Sure, to write bulletproof subprograms, you either

a) know what the compiler does, and use the specific entity form, e.g. this
is perfectly reasonable in the GNAT runtime, which has ZERO interest in
running on other compilers, and is entirely GNAT specific.

or (and we in fact prefer this in the GNAT runtime always :-)

b) use the form with only a scope suppress

I am not sure what you mean about "inherit suppress in bodies", but if
it means what I think it means, I would consider a compiler that does not
do this to be broken ... but perhaps I misunderstand.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 2:12 PM

I find Tuck's answer here insufficiently pragmatic, and it just does not
seem worth the work to try to tune up this ill-advised, ill-defined
feature in the RM (what precise entities are tested).

I have no problem with deciding not to standardize the entity form of
unsuppress. As I said before, GNAT does implement this form with very
well defined semantics, as I noted. Yes, they are not as well defined
as they might be, since the effect of the suppress is not well defined.

I find it surprising that Tuck does not see the difference between
suppress and unsuppress here!

A suppress is never critical. Any code that relies on a suppress actually
suppressing checks is clealry incorrect.

An unsuppress is very often critical. Code very often relies on a check that
is guaranteed to occur, regardless of compiler options, as a reuslt of
ensuring that the check is not suppressed.

That's a VERY big difference in practice.

The point is that you cannot simply borrow the Suppress semantics (which are
ill defined and non-portable, but it does not matter that much) for
Unsuppress in a manner that leaves them as ill defined and non-portable
(since it could matter a lot!)

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

From: Randy Brukardt
Sent: Tuesday, March 14, 2000 3:32 PM

> I'm not sure why you talk about "conforming" here.  We are talking about
> entities, not expressions, so either they denote the same entity, or
> they don't.

Not really, there are whole can of worms here I would rather leave the lid on.
For instance, are two subtypes of the same type the same or different entities
for the purpose of suppressing checks? I'd just as soon let compilers do
whatever they're going to do here.

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

From: Randy Brukardt
Sent: Tuesday, March 14, 2000 3:53 PM

> <<However, I objected to this semantics on a usage basis, as it makes it very
> difficult to write a bullet-proof subprogram that depends on checks being
> made (and exceptions raised). >>
>
> Now this must be wrong, *adding* a facility cannot make it
> harder to do something!

Robert, it's clear to me from your mail to Tucker that you understand the
problem, so I think we're a lot closer together on this than is obvious.

> Sure, to write bulletproof subprograms, you either
>
> a) know what the compiler does, and use the specific entity form, e.g. this
> is perfectly reasonable in the GNAT runtime, which has ZERO interest in
> running on other compilers, and is entirely GNAT specific.
>
> or (and we in fact prefer this in the GNAT runtime always :-)
>
> b) use the form with only a scope suppress

Well, what I want to do is to bullet-proof my code against anything that a
ham-handed maintenance programmer (which might be me!) or end-user (of Claw, for
instance) might do.

I certainly can't assume a specific compiler (rules out (a)), and I don't have
any way to prevent someone from using Suppress (..., On => ...). I could imagine
a compiler option that Suppressed checks on all entities whose names started
with 'A'. (OK, I'm reaching here). But certainly a maintenance programmer could
insert a Suppress (..., On => ...) for some reason, and my bullet-proof
subprogram isn't bullet-proof anymore.

The best way to support bullet-proof routines is for non-specific Suppress to
force *all* of the appropriate checks on. This also has the least surprise for
the user (because they actually get what they said -- does GNAT warn if a
non-specific unsuppress is leaving some checks suppressed??). But I do see the
definitional problem (although I really don't see why it is a problem to
Unsuppress everything -- there can be no confusion as to what is unsuppressed in
that case). [BTW, I don't think that changing GNAT to do just that (no other
changes) would break user programs -- at worst they would get a bit more
checking than expected in some subprogram.]

I suppose another way out of this problem would be to adopt the GNAT semantics
and to provide a Restictions identifier "No_Specific_Suppress" that I could use
as a configuration pragma in Claw (or any other code that I needed to
bullet-proof). The restriction would make any specific Suppress that reached a
unit with the restriction illegal, as well as the use of it. (If the maintenance
programmer then went ahead and removed that, well, there is only so much
bullet-proofing that is possible...)

> I am not sure what you mean about "inherit suppress in bodies", but if
> it means what I think it means, I would consider a compiler that does not
> do this to be broken ... but perhaps I misunderstand.

Janus/Ada uses a purely textual model for controlling checks, inherited from our
CP/M compilers. Anything that doesn't map cleanly into that is rejected, and
many suppresses are in fact rejected (well, ignored with a warning). This area
really deserves a rewrite (especially since the back-end will support a less
restrictive model), but since we don't have any customers who've complained
about that, it doesn't have much priority. And there would be compatibility
problems with the old Janus/Ada specific check control pragmas...

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

From: Tucker Taft
Sent: Tuesday, March 14, 2000 3:02 PM

Robert Dewar wrote:
> ...
> I find it surprising that Tuck does not see the difference between
> suppress and unsuppress here!
>
> A suppress is never critical. Any code that relies on a suppress actually
> suppressing checks is clealry incorrect.
>
> An unsuppress is very often critical. Code very often relies on a check that
> is guaranteed to occur, regardless of compiler options, as a reuslt of
> ensuring that the check is not suppressed.
>
> That's a VERY big difference in practice.

I still don't see this.  Consider the following:

    A := B;  -- check cannot fail, would like to suppress it
    C := D;  -- check failure possible at run-time; need to catch it

Now if we use a Suppress...On to suppress the check on "A := B" and due
to lack of precision it "spills over" into "C := D" then we have a
serious problem.

Similarly, if we use an Unsuppress...On to unsuppress the check on "C :=
D" and due to lack of precision it doesn't override some more global Suppress,
then we have a serious problem.

These kinds of imprecision both seem just as bad.  An overeager Suppress...On
is just as bad as a too-timid Unsuppress...On.  What am I missing?

> The point is that you cannot simply borrow the Suppress semantics (which are
> ill defined and non-portable, but it does not matter that much) for
> Unsuppress in a manner that leaves them as ill defined and non-portable
> (since it could matter a lot!)

I suppose you could say that we need a portable *lower bound* on how
much Unsuppress...On affects, and a portable *upper bound* on how much
Suppress...On affects. Both bounds seem just as important.

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

From: Robert A Duff
Sent: Tuesday, March 14, 2000 4:37 PM

> I suppose you could say that we need a portable *lower bound* on how
> much Unsuppress...On affects, and a portable *upper bound* on how much
> Suppress...On affects. Both bounds seem just as important.

Perhaps, but neither one is terribly important.  I wrote the section on
Suppress, and I spent some energy trying to nail down the rules, before
I finally decided it was impractical, as Robert has pointed out.  Note
that the Ada 83 RM didn't nail down the rules, either, but that fact was
less clear.

I would like to disallow Unsuppress...On, but Robert says GNAT will keep
it (and I agree that ACT would be foolish to remove it at this point).
Therefore, no matter what the ARG does, there *will* be Unsuppress...On,
and it *will* be non-portable.  We should just live with that fact.

The average user isn't going to understand some complicated set of rules
about On=> (which leads to the same sort of bugs you mention above).  So
why don't we just give up and say it's impl-def?  Is that so horrible?

By the way, I don't really understand Randy's concern:

> We distribute the Claw bindings as source code. We do this so customers can
> recompile it on a new version of a compiler, or on a different compiler,
> without have to depend on us to support it for them. Clearly, this means
> that we have limited control over the compiler options used when compiling
> the source. We want to make the source code as bullet-proof as possible,
> because we don't want to have to spend lots of technical support time
> tracking down problems. Thus, we try to write the code as generically as
> possible, so that the choice of compiler options does not affect the code.

Are you worried that *you* might put an outer Suppress...On in the code?
Or are you worried that the customer might insert one?  If the former,
my answer is, "Don't do that."  If the latter, my answer is that of
course if users edit the sources they might break things.

You're correct that Suppress...On is the tool of the devil.  It
shouldn't be in the language in the first place.  But obviously we can't
get rid of it now.  So just don't use it.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 4:26 PM

<<These kinds of imprecision both seem just as bad.  An overeager Suppress...On
is just as bad as a too-timid Unsuppress...On.  What am I missing?
>>

You are inventing bugs, we are not talking about an over-eager suppress here,
that would be a bug, bugs are a BAD THING, and must be avoided.

We are talking about under-eager suppresses. For example:

  A := B;

if you suppress constraint check on A (or B) that might or might not
suppress this check, it certainly WILL NOT suppress a check on C := D.

But your code can never count on a suppress being effective anyway.

On the other hand, if you have a scope suppress set, and you unsuppress
on A and B, and expect this to make

  A := B;

not raise an exception, then the under-eager unsuppress WILL cause a
problem.

<<These kinds of imprecision both seem just as bad.  An overeager Suppress...On
is just as bad as a too-timid Unsuppress...On.  What am I missing?
>>

The overeager Suppress is a pure invention, and nothing to do with anything
we are discussing here.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 4:41 PM

<<I would like to disallow Unsuppress...On, but Robert says GNAT will keep
it (and I agree that ACT would be foolish to remove it at this point).
Therefore, no matter what the ARG does, there *will* be Unsuppress...On,
and it *will* be non-portable.  We should just live with that fact.
>>

Seems reasonable to me ...

<<The average user isn't going to understand some complicated set of rules
about On=> (which leads to the same sort of bugs you mention above).  So
why don't we just give up and say it's impl-def?  Is that so horrible?
>>

Incidentally, note that the GNAT rule is *very* easy to explain and for
people to understand (the On form of Unsuppress does nothing but cancel
the effects of an identical active Suppress ON, and if there is none,
does nothing at all).

<<Are you worried that *you* might put an outer Suppress...On in the code?
Or are you worried that the customer might insert one?  If the former,
my answer is, "Don't do that."  If the latter, my answer is that of
>>

I understand perfectly the concern here, and we have exactly the same
effect in the GNAT runtime. You want to write code that can be compiled
with checks on or checks off (compiler option) and stlil be functionally
correct. This was the motivation for Unsuppress in the first place.

Telling people "don't do that" is not an acceptable solution, and in any
case it makes very good sense to suppress checks on the GNAT runtime, it
removes almost all the checks (all but the very few that are functionally
necessary and which are assured by Unsuppress).

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 5:46 PM
Subject: RE: AI 224 suppress/unsuppress details

<<Well, what I want to do is to bullet-proof my code against anything that a
ham-handed maintenance programmer (which might be me!) or end-user (of Claw,
for instance) might do.
>>

Well your maintenance programmer could be incompetent in many other ways,
I don't see this as very convincing, but I understand your point.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 5:47 PM

<<Not really, there are whole can of worms here I would rather leave the lid
on. For instance, are two subtypes of the same type the same or different
entities for the purpose of suppressing checks? I'd just as soon let
compilers do whatever they're going to do here.
>>

They are different entities, that's quite clear from the RM.

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

From: Robert A Duff
Sent: Tuesday, March 14, 2000 6:16 PM

> Well, what I want to do is to bullet-proof my code against anything that a
> ham-handed maintenance programmer (which might be me!) or end-user (of Claw,
> for instance) might do.

That's easy: a coding convention that says "don't use On =>".

It seems sort of like you're worrying that somebody, somewhere, might do
an Unchecked_Conversion that would violate the invariants of my package,
and I want to protect my package from that.  Well, you can't, in Ada.

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

From: Robert A Duff
Sent: Tuesday, March 14, 2000 6:27 PM

> Incidentally, note that the GNAT rule is *very* easy to explain and for
> people to understand (the On form of Unsuppress does nothing but cancel
> the effects of an identical active Suppress ON, and if there is none,
> does nothing at all).

And if it's also easy to implement, then I'm for it.

My main concern here is that we don't cause a lot of implementation
effort for these "On =>"'s, which are very close to being totally
useless.

> <<Are you worried that *you* might put an outer Suppress...On in the code?
> Or are you worried that the customer might insert one?  If the former,
> my answer is, "Don't do that."  If the latter, my answer is that of
> >>
>
> I understand perfectly the concern here, and we have exactly the same
> effect in the GNAT runtime. You want to write code that can be compiled
> with checks on or checks off (compiler option) and stlil be functionally
> correct. This was the motivation for Unsuppress in the first place.
>
> Telling people "don't do that" is not an acceptable solution, and in any
> case it makes very good sense to suppress checks on the GNAT runtime, it
> removes almost all the checks (all but the very few that are functionally
> necessary and which are assured by Unsuppress).

No, I think you miss Randy's point (as do I).  I agree with the above --
that's exactly how I use pragma Unsuppress -- I want to have a run-time
system that can be compiled with checks on or off (a global setting) and
work either way.  So I mark parts of the code with pragma Unsuppress
that I know really need the checks.  But I never seem to need "On =>".

Randy, on the other hand, seems to be worried about an outer
Suppress...On versus an inner Unsupress without On.  I'm not worried
about customers who secretly add Suppress...On pragmas to key variables
inside the run-time system, any more than I'm worried about customers
who add any other kind of bug.

You say, "it makes very good sense to suppress checks on the GNAT
runtime", which I agree with.  But it doesn't make sense to add "pragma
Suppress(Overflow_Check, On => The_Result_Of_The_Exponentiation_Op);" to
some random part of the GNAT runtime.

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

From: Robert Dewar
Sent: Tuesday, March 14, 2000 7:16 PM

<<You say, "it makes very good sense to suppress checks on the GNAT
runtime", which I agree with.  But it doesn't make sense to add "pragma
Suppress(Overflow_Check, On => The_Result_Of_The_Exponentiation_Op);" to
some random part of the GNAT runtime.
>>

No, definitely not, and I am in agreement with the rest of Bob's coments as
well here.

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

From: Robert Dewar
Sent: Wednesday, March 15, 2000 2:18 PM

<<That's not helpful. Five years from now, I am not likely to remember that
I'm not supposed to use Suppress...On for  some obscure reason. And other
programmers who might work on the source don't know about this discussion in
the first place.
>>

I find this argument *very* weak, and would not take it into
consideration. If you are saying that the standard must enforce
your particular coding standards that seems unreasonable.

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

From: Randy Brukardt
Sent: Wednesday, March 15, 2000 6:59 PM

> <<That's not helpful. Five years from now, I am not likely to remember that
> I'm not supposed to use Suppress...On for  some obscure reason. And other
> programmers who might work on the source don't know about this discussion in
> the first place.
> >>
>
> I find this argument *very* weak, and would not take it into
> consideration. If you are saying that the standard must enforce
> your particular coding standards that seems unreasonable.

I'm pretty tired of this discussion, and we've agreed on all of the other
points, but I'll make one last try here.

I would agree with your comment on coding standards. The problem is, the only
reason coding standards are involved at all is that non-specific Unsuppress is
defined not to affect Suppress...On. If

    pragma Unsuppress (All_Checks);

insisted that all checks are performed (no matter how they were suppressed),
then the subject of "coding standards" would not come up.

I offered a compromise position of having the language enforce the "coding
standard" of no Suppress...On pragmas, but people consider that "weak".

Well, fine. I withdraw that compromise.

I have heard no technical argument as to why pragma Unsuppress (without an "On")
cannot revoke checks suppressed by any kind of Suppress pragma. The arguments
against Unsuppress...On do not apply here: "Make all checks" is unambiguous and
certainly not implementation-dependent.

I haven't heard any implementation-related arguments against this, either. I
suppose there might be some, but I'd like to hear them.

The only arguments I've heard against it are (1) it makes the semantics of
Unsuppress...On confusing; and (2) GNAT doesn't do it that way.

(1) is a red herring now, as we've decided that the RM will not contain
Unsuppress...On (other than a permission for GNAT and other compilers to include
it with implementation-defined semantics). What an implementation-defined pragma
means to some compiler is entirely up to that implementor. And anyone that wants
portable code certainly won't use it.

(2) doesn't seem real either. Robert has said that he considers any program that
depends on a specific check being suppressed is broken. If GNAT was changed to
"do it this way" (that is, having the RM-defined Unsuppress revoke checks on any
Suppress with the same check name, including Suppress...On), it certainly could
not break any existing code. The only harm it could possibly do is cause some
check to be made that was not made before. And Robert has said that any program
which failed as a result would be broken. Thus I find the GNAT argument -- in
this one specific case -- to be "very weak", as Robert put it.

Certainly, this would be a far less disruptive change than forcing GNAT to
"unimplement" something, or changing the meaning of Unsuppress...On. And it
makes the meaning of Unsuppress far more intuitive, and makes it useful in the
*absence* of coding standards. And it has simpler RM wording as well (because we
don't have discuss Suppress...On separately when defining Unsuppress).

So I await any technical or implementation arguments against this.

                        Randy.

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

From: Robert Dewar
Sent: Wednesday, March 15, 2000 7:13 PM

<<(2) doesn't seem real either. Robert has said that he considers any program
that depends on a specific check being suppressed is broken. If GNAT was
changed to "do it this way" (that is, having the RM-defined Unsuppress
revoke checks on any Suppress with the same check name, including
Suppress...On), it certainly could not break any existing code. The only
harm it could possibly do is cause some check to be made that was not made
before. And Robert has said that any program which failed as a result would
be broken. Thus I find the GNAT argument -- in this one specific case -- to
be "very weak", as Robert put it.
>>

I find that a possibility, and do not strongly object to this idea.

However, in practice I find the only useful use of Unsuppress to be
to undo a compiler option that suppresses checks.

I find it a big bogus to worry about a program that uses a suppress on
a specific entity and in a nested range needs to unsuppress it without
knowing that it is there.

Remember we are only talking static nesting here, i.e. the suppress
and unsuppress would have to be in the same package for Randy's worry
to apply.

It seems *awfully* theoretical to me ...


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

From: Randy Brukardt
Sent: Wednesday, March 15, 2000 7:35 PM

> I find it a big bogus to worry about a program that uses a suppress on
> a specific entity and in a nested range needs to unsuppress it without
> knowing that it is there.

A Suppress...On can be used in a package specification, and would apply to that
entity anywhere it is used. (It applies to the entire scope of the entity, which
essentially is the whole program).

That's the case I'm worried about. I don't find that all that unlikely; it
certainly doesn't have to be in the same source file.

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

From: Robert Dewar
Sent: Wednesday, March 15, 2000 8:58 PM

<<A Suppress...On can be used in a package specification, and would apply to
that entity anywhere it is used. (It applies to the entire scope of the
entity, which essentially is the whole program).

That's the case I'm worried about. I don't find that all that unlikely; it
certainly doesn't have to be in the same source file.
>>

I find this level of worry completely and utterly unconvincing. This is
simply not what Unsuppress is useful for in practice.

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

From: Jean-Pierre Rosen
Sent: Thursday, March 16, 2000 2:39 AM

I must confess that I'm getting lost in this discussion, but it seems clear
to me that the difficulty is in the definition of Unsuppress in relation to
Suppress.
Why not abandon the idea of "unsuppressing", and rather have a pragma Force,
with a simpler semantics, something like:

pragma Force (identifier[, [On =>] name]);
The values of "identifier" are as defined for pragma Suppress. When in the
scope of a pragma Force, the corresponding checks are always in effect. Any
inner pragma Suppress will have no effect on entities to which a pragma
Force applies".

There is no contradiction, since a pragma Suppress can always be ignored.
There is no incompatibility, since existing implementation can still provide
pragma Unsuppress if they wish.

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

From: Randy Brukardt
Sent: Thursday, March 16, 2000 11:02 AM

> Why not abandon the idea of "unsuppressing", and rather have
> a pragma Force,
> with a simpler semantics, something like:
>
> pragma Force (identifier[, [On =>] name]);

This is *exactly* where I started with pragma "Require". With exactly the
definition that Jean-Pierre recommends.

Of course, I was shouted down on that one. I think it would be pretty crazy to
revert the entire thing to the original version.

As it stands, I plan to write it up only with non-specific Unsuppress, an
implementation permission to support Unsuppress...On with implementation-defined
semantics, and the rule I outlined earlier (because it is easier to describe and
use). If it turns out that there are substantial implementation concerns, we can
revisit that detail.

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

From: Robert A Duff
Sent: Thursday, March 16, 2000 8:06 AM

> I'm pretty tired of this discussion, and we've agreed on all of the other
> points, but I'll make one last try here.

As usual, we spend the most energy arguing about the least important
issues.  ;-)

I can go along with Randy's idea, so long as we agree that it's not
harder to implement.  I don't have evidence that it *is* harder.
I just think implementation difficulty should be the overriding concern,
given that "On=>" is so rarely used, and ill-defined anyway.

We have implemented pragma Unsuppress at AverStar, and I *think* we did
this "On=>" stuff the same way as GNAT.

So: I could agree to any of (1) the GNAT way, (2) Randy's way, or (3)
implementation defined.

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

From: Tucker Taft
Sent: Thursday, March 16, 2000 11:08 PM

Randy Brukardt wrote:
>
> I have heard no technical argument as to why pragma Unsuppress (without an
> "On") cannot revoke checks suppressed by any kind of Suppress pragma. The
> arguments against Unsuppress...On do not apply here: "Make all checks" is
> unambiguous and certainly not implementation-dependent.

Does Unsuppress override Suppress...On, even if the Suppress...On is in
an inner scope?  If not, implementation gets more difficult.  If we can
assume that Unsuppress overrides Suppress, no matter which came first,
then that is fairly straightforward -- we first check whether any
Unsuppress's apply.  If so, we definitely do the check.  If not, we do
what we currently do to decide whether any Suppress's apply.

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

From: Jean-Pierre Rosen
Sent: Friday, March 17, 2000 2:41 AM

This is basically what I suggested. And since an Unsuppress would not be
illegal if there is no corresponding Suppress, I suggested a more
appropriate name like "Force" or "Require" (Randy's first suggestion). Does
anyone remember why this initial suggestion was rejected ?

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

From: Robert Dewar
Sent: Thursday, March 16, 2000 11:56 PM

<<I can go along with Randy's idea, so long as we agree that it's not
harder to implement.  I don't have evidence that it *is* harder.
I just think implementation difficulty should be the overriding concern,
given that "On=>" is so rarely used, and ill-defined anyway.
>>

It definitely *is* harder to implement, in fact it is not easily within
range at all without a lot of fiddling for GNAT. Why? Because now it is
not good enough to hjust have one status bit for each check, we need 2,
since suppress/unsuppress is no longer equivalent to just turning the
suppress flag on and then turning it off.

I don't find Randy's suggestion unreasonable, but I don't think GNAT
would follow this implementation path.

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

From: Robert Dewar
Sent: Friday, March 17, 2000 12:13 AM

<<As it stands, I plan to write it up only with non-specific Unsuppress, an
implementation permission to support Unsuppress...On with
implementation-defined semantics, and the rule I outlined earlier (because
it is easier to describe and use). If it turns out that there are
substantial implementation concerns, we can revisit that detail.
>>

If I understand the rule that Randy refers to is a fule that an Unsuppress
overrides any inner Suppress, or am I confused.

Anyway, one thing to be clear on here is that GNAT is NOT about to make
any incompatible changes to Unsuppress. This is a pragma we implemented
years ago, and we are not about to cause incompatibilities of this kind.

My feeling is that if the result of this discussion on Unsuppress is
inconmaptible with GNAT, then the pragma should have some other name

It makes no sense to copy an existing feature from one compiler in a form
different from what is implemented. This leads to more *divergence* when
the object of the excercise is *convergence*.

I am not being stubborn here, just pragmatic, we cannot cause our customers
problems due to non-upwards compatible changes.

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

From: Robert Dewar
Sent: Friday, March 17, 2000 7:57 AM

<<This is basically what I suggested. And since an Unsuppress would not be
illegal if there is no corresponding Suppress, I suggested a more
appropriate name like "Force" or "Require" (Randy's first suggestion). Does
anyone remember why this initial suggestion was rejected ? >>

Well for one thing, it does not address the requirement that Unsuppress was
intended to address (and for which it has been succesfully used for years
in the GNAT technology!)

Since the entire discussion had a genesis of looking at the Unsuppress
feature in GNAT to wonder whether it was worth semi-standardizing, this
is a bit peculiar!

There are two issues here

  1. Worrying about the seldom used "On" forms of Suppress and Unsuppress.
     It is fine to make sure we don't overspecify or cause implementation
     burdens here, but worrying about the utility is a complete waste of
     time in my opinion.

  2. The idea that an unsuppress is illegal if there is no corresponding
     suppress completely misses the primary and very useful function of
     Unsuppress, and makes Force/Require completely useless for this
     purpose.

Perhaps it would be a good idea to restate why Unsuppress is useful in the
GNAT technology, and why it has been extensively used for years there.

  If you are writing a library (the issue first arose in the GNAT runtime
  library), then run-time checks in the library have two functions. One to
  catch bugs in the library itself, and two to report errros that must be
  reported back to the user (e.g. a Constraint_Error in Calendar, converted
  back to Time_Error).

  It is useful to be able to write libraries so that they can be compiled
  with or without checks, with the understanding being that compiling
  without checks will remove debugging checks. But you can't remove
  critical checks of the second kind.

  If we did not have Unsuppress, then we would have to have a complex
  set of rules in the make files about units that must always be
  compiled with checks on.

The idea above for Force/Require

  a) has nothing to do with the pragma Unsuppress in GNAT

  b) is as far as I am concerned completely useless

  c) raises significant implementation issues

  d) has not been suggested by any actual user

There ... is that a good enough reason for the ARG not rushing around and
standardizing a new feature out of the blue for which there is zero demand? :-)

Seriously, I can't imagine GNAT implementing the Force/Require in the above
form, and if the ARG gets into the business of modfiying the language for no
good reason and causing implementation effort for no gain, it will undermine
itself if you ask me.

P.S. I think the exactly right thing here is to document ONLY the effect
of Suppress and Unsuppress as they interact with one another for the
normal (no ON) case

In the write up you say

a) implementations can provide the ON form of Unsuppress, but are not
required. For my taste I would require that the implementation of On
for Unsuppress, implemented be the existing GNAT interpretation, since
I see no point in allowing or encouraging diversity in a non-required
non-critical feature. Once again, the GNAT interpretation is that the
only effect of On in Unsuppress is to cancel the effect (whatever that
might be) of a previous On in a Suppress for the same entity.

But I don't really care much on this incrdibly unimportant issue, the only
important thing is to avoid over specification and implementation
difficulties (it obviously does not make it hard to implement to
say "do X, but if you don't want to, don't do it" :-)

b) The effect of a general Unsuppress is implementation defined with regard
to whether it affects specific Suppress with On clauses. Since the effect
of such suppresses is implementation defined in the first place, this seems
quite fine.

Actually I think the definition of Suppress (On =>...) is not even
impleenmtation defined, but implementation dependent ...

Again b) is worrying about an issue that is incredibly unimportant.


My point in raising this whole issue (if people can still remember it
was me who sounded the warning here) was that we need to be careful
not to overspecify in this very unimportamt and non-critical aspect
of Unsuppress.

The one thing that should work, and is really useful is for a general
(non-On) Unsuppress to locally cancel the effects of a more global
Suppress.

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

From: Robert A Duff
Sent: Friday, March 17, 2000 9:38 AM

Robert says:

> I am not being stubborn here, just pragmatic, we cannot cause our customers
> problems due to non-upwards compatible changes.

I can't get *too* excited if the incompatibility has to do with "On=>",
but I basically agree -- it doesn't make sense for GNAT to make
gratuitous changes like this.

I do not like the idea of inventing a different-named pragma (Require,
Force, whatever).  We have a perfectly good design for Unsuppress,
except for some obscure oddities related to "On=>" -- those oddities do
not warrant new pragmas.  And there's probably a fair amount of existing
code that already uses Unsuppress quite happily.

> Actually I think the definition of Suppress (On =>...) is not even
> impleenmtation defined, but implementation dependent ...

Actually, the RM *pretends* to define it quite precisely -- RM-11.5(8) says:

    If the pragma includes a name, the permission applies only to checks
    performed on the named entity, or, for a subtype, on objects and
    values of its type.

No mention of impl-def or impl-dep.  It's only if you think about that
carefully that you realize nobody has any idea what it means for a check
to be performed "on" an entity.  I don't like that sort of wording; it
seems misleading.

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

From: David Emery
Sent: Friday, March 17, 2000 9:42 AM

Robert says:

>  I am not being stubborn here, just pragmatic, we cannot cause our customers
>  problems due to non-upwards compatible changes.

Gee, sounds like Bevin Brett :-)  :-)

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

From: Robert Dewar
Sent: Friday, March 17, 2000 10:07 AM

Right, it defintiely pretends that it is well defined, but since it isn't
as we know (recent thread having revealed this dirty little secret to those
not previously familiar -- I have been aware of this for a while :-), the
result is that it is not implemnetation defined, but implementation
dependent, i.e. need nto be documented.

We recently had a bug report from someone who did

 A := B;

and suppressed tag checks on A, and was surprised to still get an
exception :-)

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

From: Robert A Duff
Sent: Friday, March 17, 2000 10:22 AM

Did you fix the bug?  Or declare it to be a feature?  ;-)

Just curious.

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

From: Robert Dewar
Sent: Friday, March 17, 2000 10:26 AM

we declared it to be the way things were, explaining that the RM did
not require this to work (actually I really think here that the RM
if it says anything says that the test is NOT "on" A).

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

From: Randy Brukardt
Sent: Friday, March 17, 2000 3:53 PM

> If I understand the rule that Randy refers to is a rule that an Unsuppress
> overrides any inner Suppress, or am I confused.

You are confused. We were over all of that the first time with "Require".

An Unsuppress overrides any outer or preceding Suppress only, including
Suppress...On. An inner Suppress still can suppress checks, even if there is an
outer Suppress.

> Anyway, one thing to be clear on here is that GNAT is NOT about to make
> any incompatible changes to Unsuppress. This is a pragma we implemented
> years ago, and we are not about to cause incompatibilities of
> this kind.

As I've said many times, this ought not be incompatible except to programs that
assumed that Unsuppress did not override Suppress...On *and* depend on checks
being suppressed to function properly.

> I am not being stubborn here, just pragmatic, we cannot cause our customers
> problems due to non-upwards compatible changes.

The difference between "stubborn" and "pragmatic" is nearly indetectable here.
In any case, our primary goal is the same (I don't know if others in this
discussion have the same goal), and thus I'd expect to come up with virtually
the same solution. I just don't understand making the solution work right 98% of
the time, when it can work 100% of the time.

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

From: Randy Brukardt
Sent: Friday, March 17, 2000 4:52 PM

I find this entire discussion *extremely* frustrating. People are attributing
long rejected ideas to me, and then setting them up so Robert can use them as an
excuse to force us to adopt a very dubious (but easy to implement) definition of
this pragma.

I am here is large part because I'd rather bag groceries than program in C. If
we can't even agree on something as obvious as this, then bagging groceries is
starting to look attractive. We have to start responding to each other's
proposals, and not to ones that were rejected soundly months ago.

----

From a user perspective, and from a definitional perspective, it is clear that
an inner Unsuppress needs to revoke the permissions on outer Suppresses. But
people said that last time that it was important to allow "resuppressing"
checks, and I rewrote the AI that way. I certainly have no intention of
reverting to my original proposal, and I can see no valid reason to do so.

It is likely that there would be a small implementation cost in supporting that.
I doubt that there would be any effect on compilation times (since Suppress...On
is used so rarely), but there would be a bit of effort.

My implementation model for Suppress...On is that there is a list or lists of
all Suppress...Ons that are active. This is needed so they can be canceled when
they go out of scope. (Normally, this list would be empty, as Suppress...On is
rare). Thus, implementing Unsuppress to cancel these means walking this list to
find ones that need changing, and adding/stacking appropriate information. This
does not seem difficult or expensive. Certainly, I would not expect that you
would have to walk the entire symboltable to find such things.

----

As far as Unsuppress...On goes, I think it would be folly to try to define it at
all. There are so many questions about what entities and checks are involved
that I don't think we want to get into answering. For instance, two subtypes of
the same type are different entities, but they clearly control the same check
(11.5.(8)). What happens when one is Suppressed, and the other Unsuppressed?

Certainly, the easiest thing is to leave it implementation-defined if there is
such a pragma, and what it means if there is. I can sympathize with Robert's
concern about incompatible implementations, but this capability is simply
unimportant -- it isn't useful for bullet-proofing code (the primary concern
that both Robert and I have expressed here). I wouldn't be surprised that if
GNAT were to unimplement it (which I am *not* proposing!), that they would find
no one is using it.

It seems clear to me that GNAT does what is easiest to implement, which is what
happens when an implementor defines capabilities. That is not necessarily the
best thing for users, or even for other implementors. It would be a bad idea to
adopt these very pragmatic definitions blindly, just as it is a bad idea to
diverge too much from what works.

----

You want to talk about stubborn, I'll give you stubborn. I've been trying to
build a reasonable consensus on this topic, but I am beginning to think that the
effort has been wasted. I'm going to write up a reasonable proposal, and them
I'm going to fight at every level to adopt it. And I don't want to talk about
this anymore until I've had time to properly write up that proposal.

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

From: Robert Dewar
Sent: Saturday, March 18, 2000 7:49 AM

<<An Unsuppress overrides any outer or preceding Suppress only, including
Suppress...On. An inner Suppress still can suppress checks, even if there is
an outer Suppress.
>>

This is a severe implementation burden for absolutely no useful gain in
my opinion. It means that the effect of

Suppress (Range_Check);
Unsuppress (Range_Check);

is not equivalent to nothing, and that means that we need a whole set of
extra flags to record the presence of the Unsuppress.

And what is this for? Just to deal with the case where someone uses an
implementation-defined Suppress (.., On=>) and then does an Unsuppress
in an inner range.

We are making the great mistake here of letting best be the enemy of good.
And the trouble is that this means we will fail in our goal of improving
commonality.

If the above spec is adopted, it is quite unlikely in my view that GNAT
could justify a significant implementation effort of no value to our
users, just so some weird implementation dependent use of
Suppress ( .. On=>) is better defined.

Why can't we just back off here and define Unsuppress (X) as undoing
the effect of Suppress (X) or Suppress (All_Checks) or an equivalent
compilation option, and say that the handling of the On case is
implementation dependent (both for Suppress and Unsuppress).

That way we get 99% of the utility of the feature with a minimum of
hassle.

Personally I think it would be quite reasonable for an Ada 95 compiler
to completely ignore the Suppress (.., On =>) form, and of course if
the above spec were adopted, the argument for doing that would be
even stronger. If we were doing GNAT from scratch right now, probably
we would do that even without the spec above, and certainly with the
above spec, it would be crazy to go to a lot of effort. But GNAT is
out there, and we do not feel like making incompatible changes. Indeed,
other compilers have probably implemented Suppress (xxx, On=>) to do
something or other ...

Think of it this way, in any implementation (talking only about the
general case without ON), Suppress does something, and must be handled
in a stack like manner so that as you unwind you get back to where
you want.

Unsuppress merely undoes whatever was done, and can almost certainly
share the same stack like mechanism. So it is a minimum implementation
burden.

I must say this whole discussion is an amazing example of how the ARG
can take something simple, and turn it complex by arguing about marginal
cases of no interest to the real world. It's bad enough to do that during
the language design itself, but it really is not acceptable at all in
trying to do URG type activities.

So, bottom line, here is how I think Unsuppress should be written up.


Unsupress (xxx) has the effect of undoing any previous or outer level
Suppress for the same check (or all checks, or an equivalent
compiler option). Suppress and Unsuppress stack and unstack (just
as Suppress does now).

The effect of Unsuppress on a previous or higher level (Suppress, On=>xxx)
is implementation defined.

The effect of Unsuppress (xxx, On =>xxx) is implementatoin defined.

And while we are at it, it might be nice to point out that
Suppress (xxx, On=>xxx) is implemenmtation dependent in the first
place.

For my taste, I would have added a guarantee that

Unsuppress (xxx, On => yyy)

undoes the effect of an identical outer level or previous Suppress, but
I really don't care if this is in or not. At least it should be
implementation advice.

--------
more thoughts:

I have never ever ever seen anyone do a pragma suppress with ON as a
configuration pragma, in fact I don't think it's legal, since how could
you have a valid LOCAL_NAME.

So worrying about the effect of Unsuppress on such a Suppress is just way
outside the original areas of concern for this pragma.

The pragma as simply defined is a really useful feature, attempting to
fancy it up by over-worrying about the ON case is a way of making it
much less useful in my opinion.

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

From: Robert Dewar
Sent: Saturday, March 18, 2000 8:36 AM

<<I find this entire discussion *extremely* frustrating. People are
attributing long rejected ideas to me, and then setting them up so Robert
can use them as an excuse to force us to adopt a very dubious (but easy to
implement) definition of this pragma.
>>

OK, look here, I now find he entire ARG work on this of no interest to
us here at ACT. Please do whatever you like, but please do not expect
ACT to pay any attention to the result if it requires lots of implementatoin
effort for no possible gain to our customers.

I am not trying to FORCE anyone to do anything, I am just pointing out the
reality that as a company we are not going to spend resources on modifying
a feature that we have had for years and is in a form that is useful just
because the ARG thinks that some change is useful. Of course useful changes
are welcome, but the change here is in my opinion damaging.

I would advise however that if the ARG wants to define a feature that is
incompatble with the existing Unsuppress pragma of GNAT that they kindly
choose another name to avoid confusion among the large number of Ada 95
users who are using Unsuppress today. So by all means go back to Force or
Require or whatever you like.

My point is twofold

1. If the ARG defines Unsuppress, it should be upwards consistent with the
existing implementation in GNAT.

2. Anything the ARG does here should be easy to implement and generally
useful.

(and the reason for 2 is that vendors will simply not implement features
that do not meet these two criteria).

In our opinion here, Randy's formulation of Unsuppress does not meet either
of the criteria of requirement 2 above.

But I am not trying to force anyone to do anything. Frankly I think the
work of the ARG on this particular point is rather marginal, especially
for us, since we already have a perfectly good implementation of this
feature, which

a) is well defined, and the definition is easy to understand

b) it meets our customers requirements, no one has ever suggested any
changes or enhancements to this feature.

Really, Randy, to resort to non-technical arguments that I am trying to
force people to do things is quite inappropriate to this discussion.

Anyway, I will not partipate further in this discussion, so do not expect
any more notes from me. I think my position (representing the position
of ACT) is clear at this stage. Others will have to take it from here.

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

From: Randy Brukardt
Sent: Sunday, March 19, 2000 7:54 PM

First of all, let me apologize for any unintentional personal attacks that I may
have made in my frustration on Friday. I was always taught to attack the ideas,
not the person, and I always try to follow that in e-mail. If I crossed over
that invisible line, I am sorry.

Robert suggested:

> Why can't we just back off here and define Unsuppress (X) as undoing
> the effect of Suppress (X) or Suppress (All_Checks) or an equivalent
> compilation option, and say that the handling of the On case is
> implementation dependent (both for Suppress and Unsuppress).

For commonality purposes, I could agree to this (indeed, I was thinking of
proposing it on Friday). But sooner or later these commonality features are
going to get added to the standard (unless of course Ada is dead, but then why
even bother with commonality?). And when they do, I don't think that users of
Ada, the ones that vote on the new standards, are going to like a feature that
appears to be 90% implementation-defined. (Even if in practice, it is more like
10% implementation-defined).

So I would rather get this right now, rather than having to deal with it again
some years down the road, when even more implementations exist and we may be
boxed into a corner.

----

Anyway, I think we've gotten beyond the "light" stage of this discussion, so
it's time to stop discussing it for a while.

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

From: Robert Dewar
Sent: Sunday, March 19, 2000 9:31 PM

<<For commonality purposes, I could agree to this (indeed, I was thinking of
proposing it on Friday). But sooner or later these commonality features are
going to get added to the standard (unless of course Ada is dead, but then
why even bother with commonality?). And when they do, I don't think that
users of Ada, the ones that vote on the new standards, are going to like a
feature that appears to be 90% implementation-defined. (Even if in practice,
it is more like 10% implementation-defined).
>>

Nope, in practice the existing Suppress (On =>) is 90% implementation
dependent, and it has not bothered anyone.

Getting it "right" can ONLY mean fixing this implementation dependence
and that is an utter waste of time.

I can't understand why the ARG keeps wanting to waste time on issues that
have precisely ZERO effect on the Ada user community.

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

From: Robert Dewar
Sent: Sunday, March 19, 2000 9:19 PM

Note that my proposal here was completely implementation independent,
except to the extent that Suppress (... On=>) is implementatoin dependent.

My suggestion is that an Unsuppress of any kind simply cancels a matching
Suppress in an outer scope, or, if there is no matching Unsuppress in
an outer scope has no effect.

So Unsuppress (...,On=>) only has effect if there is a corresponding
Siuppress on the same entity, and has the effect of cancelling it.

This is easy to describe, easy to implement, and means that the only
level of implementation dependence is what is already there in the language.

This is *exactly* the current GNAT implementation.

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

From: Tucker Taft
Sent: Monday, March 20, 2000 9:55 AM

Robert Dewar wrote:
> ...
> This is *exactly* the current GNAT implementation.

I still haven't heard what GNAT does about inheritance from
spec to body, and from stub to subunit, and how this interacts
with source-wide [un]suppress configuration pragmas.  That is really
all I wanted to know when I reignited this firestorm.

Is there someone on the ACT team who could give the details on these
two topics, and how they interact?

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

From: Robert Dewar
Sent: Monday, March 20, 2000 10:38 AM

<<I still haven't heard what GNAT does about inheritance from
spec to body, and from stub to subunit, and how this interacts
with source-wide [un]suppress configuration pragmas.  That is really
all I wanted to know when I reignited this firestorm.
>>

We inherit from spec to body, I am not sure what you mean about
inheriting from stub to subunit, since a stub cannot contain a pragma???

I also don't quite understand the "source wide" issue.

The configuration pragmas are at the outer level, semantics stack from
there, perhaps you could give a specific example of what you are asking
about.

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

From: Tucker Taft
Sent: Monday, March 20, 2000 12:05 PM

Robert Dewar wrote:
>
> <<I still haven't heard what GNAT does about inheritance from
> spec to body, and from stub to subunit, and how this interacts
> with source-wide [un]suppress configuration pragmas.  That is really
> all I wanted to know when I reignited this firestorm.
> >>
>
> We inherit from spec to body, I am not sure what you mean about
> inheriting from stub to subunit, since a stub cannot contain a pragma???

If you have a pragma [un]suppress inside a package body, and then
there is a stub inside that package body for a separately compiled
subprogram subunit, presumably the pragma's effects continue into the
subunit.

>
> I also don't quite understand the "source wide" issue.
>
> The configuration pragmas are at the outer level, semantics stack from
> there, perhaps you could give a specific example of what you are asking
> about.

I did give an example in my original mail, but that has been buried under
a ream of other responses.

Let's take the package spec/body situation.  Suppose inside the package
spec there is a pragma suppress.  Presumably that is "felt" inside the
package body as well.  But what about a configuration pragma in the
file containing the body?  Does that supersede the pragma inherited
from the package spec (presuming one is a pragma suppress, and the
other is a pragma unsuppress)?

Another question is whether configuration pragmas in the source file
containing the package spec are inherited by the package body, even
though the package body is in a different source file.

Those are the questions I really want answered...

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

From: Robert Dewar
Sent: Monday, March 20, 2000 12:13 PM

<<Let's take the package spec/body situation.  Suppose inside the package
spec there is a pragma suppress.  Presumably that is "felt" inside the
package body as well.  But what about a configuration pragma in the
file containing the body?  Does that supersede the pragma inherited
from the package spec (presuming one is a pragma suppress, and the
other is a pragma unsuppress)?
>>

The package spec one would override the configuration pragma for both
the spec and body, this clearly seems what you want in the only case
where you ever use Unsuppress in practice.

<<Another question is whether configuration pragmas in the source file
containing the package spec are inherited by the package body, even
though the package body is in a different source file.
>>

Yes, they are for GNAT, again that seems to me to be what you want.

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

From: Robert Dewar
Sent: Monday, March 20, 2000 12:12 PM

<<If you have a pragma [un]suppress inside a package body, and then
there is a stub inside that package body for a separately compiled
subprogram subunit, presumably the pragma's effects continue into the
subunit.
>>

Ah, yes, you were not asking from stub to subunit then but rather
from preceding declarative region to the subunit. Yes of course
we inherit here, it is clearly required by the RM> Sure you can
cheat (you can completely ignore suppress for example), but it  is
clear there is no semantic issue here.

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

From: Randy Brukardt [Editor]
Sent: Thursday, March 23, 2000

If the implementation burden of supporting non-specific Unsuppress
canceling specific Suppress is too great, I would prefer that it be
handled by adding an implementation permission to that effect. Doing
so would avoid needing to define too carefully the matching rules of
Robert's alternative rules.

Note that I left Unsuppress(..., On => ...) defined in the standard.
It seems to make more sense to leave the basic definition of the pragma
intact, especially since there is already a blanket permission to not
support any of these pragmas. And leaving the parameter defined makes it
a lot easier to describe exactly what is implementation defined.

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

From: Tucker Taft
Sent: Friday, March 24, 2000 6:33 AM

Randy Brukardt wrote:
>
> I've posted a revised AI-224 on the ACAA web site (www.ada-auth.org/~acats)
>

I hate to restart this firestorm, but I believe you still don't adequately
deal with configuration pragmas that apply to a particular source file.
Are their effects inherited by bodies that are in different source files,
if the spec is in a file that contains a config pragma?

If so, and the body's file has one as well, does the body's config pragma
supersede the spec's config pragma, but *not* supersede a pragma declared
*inside* the package spec?  E.g., in this example, what is the order of precedence
for the following 3 pragmas:

    file 1:
         pragma1;

         package foo is
             pragma2;
             ...
         end foo;

    file 2:
         pragma 3;

         package body foo is
              --- what is precedence order of pragmas?
                   2 (highest), 1, 3
                   2, 3, 1
                   3,2,1
                   3,2 (1 is irrelevant here)
                   3 (1 and 2 are irrelevant here)
                   other combos?

            ...

I would dearly like to know the answer to this, as well as the rationale for the answer.
If it is already in the AI and I am too stupid to see it, could you point
out where it is, and perhaps add an example like the above (with the answer) into the AI for
stupid folks like me?  (There is discussion about declarative regions, but I don't
feel comfortable trying to figure out the rules for config pragmas based solely on implicitly
generalizing the notion of declarative region to include "file level" or "environment".)

Also, be sure to mention the suppression inheritance rules, if any, from the context of a stub
to the corresponding subunit (hopefully similar to spec/body inheritance) and how it interacts
with config pragmas (hopefully analogously to spec/body rule).


>
>                                 Randy.

Note that command-line switches might be considered roughly equivalent to config pragmas
that apply to the sources being compiled.  But of course, command-line switch interpretation
is most definitely implementation defined.  It might be worth mentioning them in the AI
in any case (maybe you already do).

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

From: Robert Dewar
Sent: Friday, March 24, 2000 6:36 AM

<<I hate to restart this firestorm, but I believe you still don't adequately
deal with configuration pragmas that apply to a particular source file.
Are their effects inherited by bodies that are in different source files,
if the spec is in a file that contains a config pragma?
>>

Robert's answers (correspond to what GNAT does) are Yes to this

If so, and the body's file has one as well, does the body's config pragma
supersede the spec's config pragma, but *not* supersede a pragma declared
*inside* the package spec?  E.g., in this example, what is the order of preceden
ce
for the following 3 pragmas:

Yes and Yes

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

From: Tucker Taft
Sent: Friday, March 24, 2000 8:47 AM

Which is equivalent to saying that the pragma precedence is
2,3,1  (inside spec, body config, spec config).

Unfortunately, this means rethinking our implementation strategy ;-).

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

From: Robert Dewar
Sent: Friday, March 24, 2000 8:58 AM

What would you prefer?

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

From: Tucker Taft
Sent: Friday, March 24, 2000 11:23 AM

The GNAT rule is OK.  However, at the moment we use the
config pragma suppression state to initialize the declarative
region suppression state when entering a package, and then save
the suppression state for use when we get to the body.
At that point we could put the body config either in front or
in back of the spec info, but we couldn't put it in the "middle"
between the spec config and the spec-internal pragma.

Hence, we could relatively easily handle a precedence of:

   body config, spec-internal, spec config
 or
   spec-internal, spec config, body config

but not as easily handle:

   spec-internal, body config, spec config

since we have already "combined" spec-internal and spec-config in
the information we saved when we reached the end of the package spec.

For what it is worth, of the two we can more easily handle, I prefer
giving precedence to the body config pragma, since that is the one
that is sitting there visible in the source file containing the body.
This would make a "config" pragma roughly equivalent to inserting
the pragma immediately *within* each of the compilation units in the
file, thereby overriding pragmas inherited from the spec/stub context.

At this point, however, I am more interested in getting a definitive
answer, and living with it, than debating all the pros and cons.

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

From: Robert Dewar
Sent: Friday, March 24, 2000 3:07 PM

Let's make absolutely sure we know what GNAT does, can you prepare a
test program (just use a simple range check as the example perhaps).

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

From: Randy Brukardt
Sent: Friday, March 24, 2000 2:52 PM

> I hate to restart this firestorm, but I believe you still don't adequately
> deal with configuration pragmas that apply to a particular source file.
> Are their effects inherited by bodies that are in different source files,
> if the spec is in a file that contains a config pragma?

I do deal with them in the AI, but I really don't think that going further
is appropriate in the pragma Unsuppress AI. But in any case, I don't expect
a firestorm here, because I at least don't care much either way. (With one
exception, noted below).

> If so, and the body's file has one as well, does the body's config pragma
> supersede the spec's config pragma, but *not* supersede a pragma declared
> *inside* the package spec?  E.g., in this example, what is the order of
> precedence for the following 3 pragmas:
>
>     file 1:
>          pragma1;
>
>          package foo is
>              pragma2;
>              ...
>          end foo;
>
>     file 2:
>          pragma 3;
>
>          package body foo is
>               --- what is precedence order of pragmas?
>                    2 (highest), 1, 3
>                    2, 3, 1
>                    3,2,1
>                    3,2 (1 is irrelevant here)
>                    3 (1 and 2 are irrelevant here)
>                    other combos?
>
>             ...

Assuming the three pragmas are all checking pragmas (that is,
Suppress/Unsuppress). Then my answer is as follows:

The crucial question is "what declarative region does a configuration
checking pragma apply to"?

It is clear from 10.1.5(8) that pragma 1 does not (directly) apply to the
package body. However, it might apply based on what declarative region it
applies to.

I see three possibilities here:

1) The pragma applies only to the unit in the source file. This
interpretation follows directly from 10.1.5(8), no fudge necessary.

2) The pragma applies to all units compiled after it. This, I fear, is what
the RM actually says. The pragma clearly applies to the environment
declarative region, and that never ends for a particular program.

3) The pragma somehow applies only inside of the units that it applies to.
That would give the interpretation that Robert says GNAT is using. I don't
see any justification in the standard for this interpretation, but it does
have implementation advantages.

I find the first possibility the most appealing. The second possibility is
horrible, as setting such a pragma could only be turned off by compiling
another pragma. I don't think anyone wants that.

I view inheritance of Suppress pragmas as very dangerous, and would prefer
to limit it as much as possible. In particular, the third possibility makes
it impossible to use my standard approach to testing: compile the
specifications with checking off and the bodies with checking on. (There is
very little in the way of useful checks in specifications, but there is
overhead, particularly for elaboration checks). We generally use pragmas in
the source code, controlled by Janus/Ada's conditional compilation flags.

All of that said, however, the most important thing is that compilers are
consistent here, not which interpretation is taken. And it's important to
note that this has nothing whatsoever to do with pragma Unsuppress, and
should be handled in a separate, normal AI. (Robert has said what GNAT does;
what do other compilers do?)

---

Now, to answer the other question (which I did cover in the AI).  If
interpretation 1 above is taken, pragma 3 is clearly in a declarative region
outside of the unit, while the inherited pragma 2 is clearly inside the
unit. Thus 3 is applied first, then 2, and 1 is irrelevant.

If interpretation 2 is taken, the answer is the same except that 1 applies
first, then 3, then 2.

If interpretation 3 is taken, pragmas 1, 2, and 3 clearly are inside of the
unit, so they apply in the order that they are given in. That is probably 1,
2, 3 or 1, 3, 2, depending on how the "magic" that pulls these pragmas
inside is defined. However, the 1, 2, 3 order has significant usability
problems for Unsuppress (discussed in the AI), so I hope that the "magic" is
defined so that the 1, 3, 2 order that Robert says GNAT uses is what in fact
applies.

So, I think we need a two step process here: 1) decide on the real scope of
a pragma Suppress given as a configuration pragma in a file with other
units; then
2) decide what should be said in Unsuppress to insure that the order is
correct.

(Note that the order that the pragmas are applied in only matters if we have
a pragma Unsuppress; Suppress alone is essentially order-free).

If we adopt GNAT's decision on the first question, then its implementation
is by far the best interpretation for Unsuppress, and we need to contort the
RM wording until we get that solution.

If we adopt the non-inheritance wording, then the interpretation for
Unsuppress works out properly for free.

If we need it, I can write up a sample program to determine what compilers
actually do.

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

From: Tucker Taft
Sent: Monday, March 27, 2000 2:53 PM

Robert Dewar wrote:
> ...
> <<I wonder whether we should fix this suppress...on to be more
> useful?  It certainly seems like the suppress...on should be based
> on the LHS rather than the RHS of an assignment, even though the
> RM semantics describe the assignment check in terms of a subtype
> conversion applied to the RHS.
> >>
>
> I am not sure who "we" here is. If "we" is Intermetrics, feel free to
> do whatever you like here :-)
>
> If you are suggesting that we try to define which entities should be checked
> in this and other situations, then I will repeat something I said a long
> time ago ... "that way likes madness".

It might be nice for uniformity to at least draft a set of
implementation advice for suppress...on, so that over time
our implementations might converge.  I am also curious whether
there is any consensus on what is desirable/intuitive for suppress..on
an object and how it relates to LHS and RHS of an assignment.

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

From: Robert Dewar
Sent: Monday, March 27, 2000 4:33 PM

<<It might be nice for uniformity to at least draft a set of
implementation advice for suppress...on, so that over time
our implementations might converge.  I am also curious whether
there is any consensus on what is desirable/intuitive for suppress..on
an object and how it relates to LHS and RHS of an assignment.
>>

I have no intuition here except to try to follow the RM, which suggests
that it is the subtype that is the relevant entity.

If you start trying to draft implementation advice here you will get into
a mess, particularly if you start trying to be pragmatic and figure out
what is useful.

Tuck, I guess you have not thought about this issue before. It is in fact
very familiar to me, and after all dates back to Ada 83 days. This has
always been a crufty part of the language, and my view is that it is wasted
effort to try to "fix" it.

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

From: Robert A Duff
Sent: Monday, March 27, 2000 3:45 PM

I agree with Robert here.  It's a waste of time to try to define any of
this "On=>" stuff, even as impl advice.

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

From: Tucker Taft
Sent: Monday, March 27, 2000 4:08 PM

Is this because you think the feature should not be in the language?
From my perspective, as long as it is in the language, we ought to
at least attempt to have some common approach to supporting it,
or at least enumerate the possibilities for the poor user, so they
can conclude using Suppress...On is very implementation dependent.

The current implication in the RM that Suppress...On is well-defined
is quite misleading.

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

From: Robert Dewar
Sent: Monday, March 27, 2000 4:58 PM

<<Is this because you think the feature should not be in the language?
>>

Right, it was a mistake, it has never been well defined, but this is
"well known" at this stage, and this is such an unimportant marginal
feature that it is just not worth worrying about.

I really think you are going to have a hard time getting anyone to
notice this issue, and if you do come up with a set of implementation
advice, I can't imagine spending any time trying to conform to it.

It would be unhelpful even to say that this was implementation defined,
because it would make implementations waste time documenting junk.

Yes, I understand the general principle that portability is nice, but
there are pragmatic limits :-)

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

From: Dan Eilers
Sent: Monday, March 27, 2000 5:20 PM

> Is this because you think the feature should not be in the language?

On behalf of ICC, I'd like to vote for removing this feature from the
language, so long as implementations were permitted to implemented it
for backwards compatibility with previous versions of the standard.

Our compiler does not implement Suppress...On, since we detect no
user interest in this feature.  We might change our minds if some
survey of users showed some interest.

We suspect that there might be a better way to satisfy whatever user
need there might be for Suppress...On.  For example, if a user is
suppressing access checks because objects of a particular access type
are known never to be Null, then a better approach would probably be
a pragma restriction non_null, so that violations of this constraint
could be detected on assignment rather than on dereferrence.

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

From: Robert Dewar
Sent: Monday, March 27, 2000 5:35 PM

<<Our compiler does not implement Suppress...On, since we detect no
user interest in this feature.  We might change our minds if some
survey of users showed some interest.
>>

Well I trust you implement it to the point of recognizing it and ignoring
it (otherwise you could not sign the declaration of conformance). But
ignoring it is certainly quite acceptable.

<<On behalf of ICC, I'd like to vote for removing this feature from the
language, so long as implementations were permitted to implemented it
for backwards compatibility with previous versions of the standard.
>>

Well there is no point in removing this, since that just causes unnecessary
incompatibilities, and implementing it is zero effort for compilers.

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

From: Dan Eilers
Sent: Monday, March 27, 2000 6:42 PM

> Well I trust you implement it to the point of recognizing it and ignoring
> it (otherwise you could not sign the declaration of conformance). But
> ignoring it is certainly quite acceptable.

Yes, we recognize it and ignore it, which is what we would continue to
do if the feature was declared obsolescent.

> Well there is no point in removing this, since that just causes unnecessary
> incompatibilities, and implementing it is zero effort for compilers.

There's benefit to us in removing the feature from the language.
It's much easier to explain to people why we ignore an obsolescent
language feature than it is to explain that the language designers
mistakenly included this feature.

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

From: Robert Dewar
Sent: Monday, March 27, 2000 7:23 PM

Well perhaps one could argue for moving it to the equivalent of
annex J, but removing it is undesirable, since this means that
compilers could fail to recognize it. Look at the problems we
had with Ada 95 compilers that, despite the intention to the
contrary, failed to recognize Ada 83 attributes.

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

From: Robert A Duff
Sent: Monday, March 27, 2000 5:54 PM

> Is this because you think the feature should not be in the language?

Partly.  My reasoning is:

1. When writing that part of the Ada 95 RM, I realized that the Ada 83
wording was completely bogus, so I tried hard to come up with some
wording that nailed it down.  I couldn't, so I conclude that it's hard
(or maybe I'm just stupid).

2. The feature is rarely used, so the fact that it's not well-defined
(and that its ill-definedness is hidden) is not such a big deal.

> From my perspective, as long as it is in the language, we ought to
> at least attempt to have some common approach to supporting it,
> or at least enumerate the possibilities for the poor user, so they
> can conclude using Suppress...On is very implementation dependent.

Well, I would not object to a ruling that states in plain English that,
"Suppress...On is very implementation dependent".  I just think it's a
useless (and difficult) exercise to try to nail down the semantics.

> The current implication in the RM that Suppress...On is well-defined
> is quite misleading.

Yes.  I copied that wording from Ada 83, knowing full well that it was
bogus nonsense.

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

From: Robert Dewar
Sent: Tuesday, March 28, 2000 5:42 AM

note that we don't need a sweeping statement that Suppress On=> is completely
implementation dependent (it is NOT allowed to be erroneous of itself, or
delete your hard disk etc). The only thing about it that is implementation
dependent is exactly what (sub)set of entities are tested to suppress
a given check.

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

From: Pascal Leroy
Sent: Tuesday, March 28, 2000 1:45 AM

Nailing down the semantics of Suppress...On may be aesthetically pleasing, but
as others have pointed out, it's hard, and I can't see what benefits it would
bring to the user community.

You have to be pragmatic here.  Compilers have been supporting Suppress...On for
more than 15 years.  Because the definition of this pragma is so vague, compiler
writers have implemented (1) what was reasonably easy to implement and/or (2)
what the users where interested in.

Any change to Suppress...On would cause the worst case of incompatibility:
subtle performance changes in existing programs, and programs starting to fail
because exceptions would be raised (or not raised) in different circumstances.

Speaking for Rational, we would probably not change our implementation of
Suppress...On even if the ARG came up with a precise definition.  Our users have
tuned their usage of pragma Suppress...On over time based on what we implement.
There is no reason to force them to revisit their code just because the ARG
thought that uniformity in this area was important.  The whole area of checks
suppression and optimization is vastly implementation-dependent.  We might as
well acknowledge this fact .

> The current implication in the RM that Suppress...On is well-defined
> is quite misleading.

I'd be happy with a clear and honest statement saying that Suppress...On is
unspecified.

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

From: Editor

This AI was discussed at the ARG meeting in Phoenix. Following are the
important points:

1) pragma Unsuppress (All_Checks); in a nested scope (such as a subprogram
body) is the critical use. The point of making this pragma a standard is so
this use works reliably and portably. All other uses have at least some
implementation-defined characteristics, and are much less important.
"Leakage" of *any* form of Suppress past such a pragma was considered to be
a problem.

2) Several ARG members were concerned that a method exist to "re-suppress",
because that may be needed by users to get appropriate performance. We don't
want to lock out useful techniques users are familar with.

3) The current proposal was thought to be too complex. (I think is this mainly
because of the design discussion included in it, rather than the proposal
itself.)

4) We don't want to decide the inheritance of pragma Suppress. (Note that
not inheriting is allowed by the rules [ignoring the permission to Suppress
is always allowed]).

5) The inheritance of Unsuppress is critical, and in general, we don't want
it to inherit. In particular, we want a pragma Unsuppress in a package
specification to apply only to the specification, not to bodies or subunits.

6) Defining Unsuppress as a configuration pragma, defining the "On =>"
parameter, etc. is unneeded complexity.

I was directed to looking into the possibility of defining different rules
for Unsuppress than Suppress (especially for inheritance).


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

From: Editor

An off-line discussion with Robert Dewar, Tucker Taft, Bob Duff, and
Joyce Tokar in April 2000 about the current state of On => parameters to
suppress uncovered the following facts:

In the following example:
    subtype X is Integer range 1 .. 10;
    pragma Suppress (Range_Check, On => X);
is supposed to suppress the checks on the TYPE (Integer in this case), as per
11.5(8). This is much too wide.

Averstar's compiler does not allow a pragma like the above if the subtype is
outside of the declarative part of the type. Thus, the above won't work.

If we have:
   A, B, C : X; -- X as above.
   ...
   A := B + C;
which objects need to be suppressed in order to remove the range check on := varies
from compiler to compiler. For some reason, Averstar needs the RHS object
suppressed, while GNAT and DDCI need the LHS object. Moreover, whether or not
the check is a range check or an overflow check depends on the compiler; and
so that the suppression of the check still varies.

The result of the discussion is that there is not and probably cannot be any
commonality here. However, the RM language seems to imply that these uses are
portable. Everyone agreed that the effort to fix the RM language is not
worthwhile. The best solution was felt to be to move Suppress (..., On => ...)
into Annex J (making it an obsolescent feature).

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

From: Editor

		Implementation Survey for AI-00224.

		Subtest A - Suppress(All_Checks) supported.
		Subtest B - Suppress(All_Checks) in package spec inherited in body.
		Subtest C - Suppress(All_Checks) supported as a source specific config. pragma.
		Subtest D - Suppress(All_Checks) config pragma on package spec inherited in body.
		Subtest E - Unsuppress supported.
		Subtest F - Suppress(All_Checks, On => Object) supported.
		Subtest G - Suppress(All_Checks, On => Object) inherited from package spec.
		Subtest H - Unsuppress in body overrides configuration Suppress in body.
		Subtest J - Unsuppress in spec overrides configuration Suppress in body.
		Subtest K - Suppress in spec overrides configuration Unsuppress in body.
		Subtest M - Non-specific Unsuppress overrides Suppress(All_Checks, On => Obejct).

		Subtest
Compiler	Source	  	A	B	C	D	E	F	G	H	J	K	M
Janus/Ada 3.1.2	Randy		Y	N	Y	N	Y	N	-	Y	-	-	-
GNAT 3.1.2a3	Randy		Y	N	Y	N	Y	N	-	Y	-	-	-
GNAT (version not given)
		Robert Dewar	Y	N	Y	N	Y	Y	Y	Y	-	-	Y
GNAT 3.1.3a*	Randy		Y	N	Y	N	Y	Y	Y	Y	-	-	N
Rational 3.0.2b	Randy		Y	N	Y	N	N	Y	Y	-	-	-	-
AdaMagic 3.301	Tucker Taft	Y	Y	Y	Y	Y	N	-	Y	N	Y	-
ICC (version not given)
                Dan Eilers	Y	N	Y	N	N	N	-	-	-	-	-
DDCI (version not given)
		Joyce Tokar	Y	Y	Y	X	Y	N	-	Y	Y	Y	-
OcSystems	Faez Kaiser				X
DDCI (version not given)*
		Joyce Tokar	Y	Y	Y	N	Y	Y	Y	Y	Y	Y	Y


	Y - Supported. N - Not supported. X - Compiler bug or crash. - - Not applicable.

	* - The test run on GNAT 3.13a used a modified version of Chk_224h; the original version had the same results as 3.12a3.
	The second test run on DDCI used the same modified version as used for GNAT 3.13a.

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

From: Editor

(Editor's note: the following used to be in the !Discussion of the AI. In
simplifying the AI, I removed this; but it still might be useful, so I've
attached it here.)


Alternative names (in particular "Require") were considered for this pragma.
The name Unsuppress has two problems: First, it is a dubious English word; Ada
pragmas are usually English words or phrases. Secondly, the preventative use of
this pragma is very important, but "Unsuppress" appears to denote something
that can only be used when checks actually are suppressed. This would likely
lead to the under-use of the pragma as a preventative.

Irregardless, we use "Unsuppress" as the name of the pragma. There were two
main factors for this. First, Unsuppress implies a relationship with Suppress,
which other names cannot do. Second, Unsuppress is in current use as an
extension in several compilers, and standardizing existing practice is
usually better than inventing new ideas.


An alternative definition was suggested that would eliminate the need to make
the meaning of Unsuppress with an On parameter implementation-defined.
The idea of the alternative definition is to have pragma Unsuppress revoke
a particular Suppress pragma, rather than revoking a check. Doing so
avoids the implementation dependence of what exactly is checked, because
the pragmas involved are well-defined.

However, this approach has a substantial impact on usability, and there is also
difficulty in defining exactly what is revoked, especially in the On parameter
cases.

The problems with defining what is revoked come from that fact that the check
names are not disjoint. For instance, the check name All_Checks is defined to
be the union of all defined checks. Does a checking pragma using All_Checks
match a pragma using some other check? If it does, then particular pragmas
need to be able to match sets and portions of other pragmas.

For instance:

        pragma Suppress (Access_Check);
        pragma Suppress (Index_Check);
        ....
        pragma Unsuppress (All_Checks);

In this case, does Unsuppress (All_Checks) revoke both pragmas?

Similarly:

        pragma Suppress (All_Checks);
        ....
        pragma Unsuppress (Index_Check);

In this case, does Unsuppress (Index_Check) revoke the "Index_Check" portion
of the pragma Suppress?

A similar problem occurs for the On parameter, as separate entities may not in
fact have separate checks. For instance, 11.5(8) clearly states that checks
are defined on types, not on subtypes. However, two different subtypes of the
same type are clearly separate entities. Does an Unsuppress on one of the
subtypes revoke a check suppressed on the other? These sort of questions
immediately lead back into the morass that we are trying to avoid.

This definition also suffers from a usability problem. A pragma Unsuppress
does not revoke checks on a non-matching pragma Suppress. This greatly
reduces the usefulness of the pragma as a preventative, as a pragma Suppress
added elsewhere in the source of a program can leak into a supposedly
Unsuppressed program region.

Consider:

    package Something is
        ...
        pragma Suppress (Access_Check, On => Some_Subtype);
    end Something;

    with Something;
    procedure Needs_Checks is
        pragma Unsuppress (All_Checks);
            -- Make sure that all checks are made in this unit.
        Obj : Something.Some_Subtype;
    begin
        ... Obj.all ... -- Oops, no check made here.
    exception
        when Constraint_Error => ...
    end Needs_Checks;

Since the pragma Suppress does not "match" the pragma Unsuppress, the
Access_Check on Obj is still suppressed, and the exception handler will
not be invoked. Worse, the insertion of a pragma Suppress in some unit
can break code in a unit far away. This is the sort of problem that we try to
prevent in Ada, and the cost to do so in this case is not high.

While this problem can be mitigated somewhat by expanding the matching rules,
doing so adds complications, and makes the resulting solution similar
to the one proposed.

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

From: Randy Brukardt
Sent: Thursday, November 02, 2000 10:20 PM

Following is the proposed wording of 11.5 to support Unsuppress. This is the
complete clause (except as noted); it is a lot clearer than the wording in
the AI, which notes the paragraphs changed and the reasons. I'm still
working on the !discussion section of the AI (it needs a complete rewrite
and simplification), so the whole new AI isn't available yet (probably
tomorrow).

The version is different from the last one in the following ways:

1) Specific Suppress (with On parameters) is declared obsolescent, and moved
to Annex J;

2) Pragma Unsuppress does not inherit into other compilation units other
than the one it is specified in. (Pragma Suppress in a package specification
inherits into the package body, and also into any subunits. However, this
inheritance is not widely implemented in Ada 95 compilers, and we don't want
to force compilers to support it for
Unsuppress.) Thus, we define the "region" to which Suppress and Unsuppress
applies separately.

3) The region to which a pragma Unsuppress used as a configuration pragma
applies is implementation-defined.
(I know that the ARG would rather that we did not define Unsuppress as a
configuration pragma at all, but this is necessary to support existing
implementations. See question 2 below.)

Questions:

1) I just moved the existing wording for specific Suppress to Annex J. Do we
need a statement that the checks suppressed are implementation-dependent?
(This came up multiple times in the E-Mail, but I don't know whether we want
to add that to the wording or just leave it implicit.)

2) It would be simpler to not define Unsuppress with an On parameter, and
Unsuppress as a configuration parameter. (The first being problematic, and
the second being almost useless.) The problem is, that this would be
incompatible with existing implementations. That is, when (in the distant
future) Unsuppress becomes an official part of the language, it would no
longer be legal to support it as a configuration pragma or for it to have
the additional parameter.
(Implementations are not allowed to extend language-defined pragmas.) That
would be incompatible with most of the existing implementations, especially
GNAT. To date, the consensus has been that we don't want to force GNAT or
other implementations to change. Has this changed? (I think it would be bad
policy to adopt an amendment that we would not add to the language without a
significant change, so I think we need to deal with this issue now.)

3) Other comments are welcome. But I think actual wordsmithing on this text
is premature. FYI, paragraphs 2, 9-26, 28-29, 30-31 are unchanged. I've
included them below for ease of reading.

                                Randy.

---------


11.5 Suppressing Checks


1  Checking pragmas give an implementation instructions on handling
language-defined checks. A pragma Suppress gives permission to an
implementation to omit certain language-defined checks, while a pragma
Unsuppress revokes the permission to omit checks.

2  A language-defined check (or simply, a ``check'') is one of the
situations defined by this International Standard that requires a check to
be made at run time to determine whether some condition is true. A check
fails when the condition being checked is false, causing an exception to be
raised.


                                   Syntax

3  The forms of checking pragmas are as follows:

4      pragma Suppress(identifier);
       pragma Unsuppress(identifier);

5  A checking pragma is allowed only immediately within a declarative_part,
immediately within a package_specification, or as a configuration pragma.


                               Legality Rules

6  The identifier shall be the name of a check.


                              Static Semantics

8  A checking pragma applies to the named check in a specific region (see
below), and applies to all entities in that region. A pragma Suppress
applies from the place of the pragma to the end of the innermost enclosing
declarative region. A pragma Unsuppress given in a declarative_part applies
from the place of the pragma to the end of the innermost enclosing
declarative region, but not in any subunits of that declarative_part. A
pragma Unsuppress given in a package_specification from the place of the
pragma to the end of the specification. The region to which a pragma
Unsuppress given as a configuration pragma applies is
implementation-defined.

8.1 A pragma Suppress gives permission to an implementation to omit the
named check for any entities to which it applies. A pragma Unsuppress
revokes the permission to omit the named check for any entities to which it
applies. If there is no such permission at the point of a pragma Unsuppress,
then the pragma has no effect. If permission has been given to suppress a
given check, the check is said to be suppressed.

9  The following are the language-defined checks:

(* Omitted, these are not modified by this proposal *)

                             Erroneous Execution

26  If a given check has been suppressed, and the corresponding error
situation occurs, the execution of the program is erroneous.


                         Implementation Permissions

27  An implementation is allowed to place restrictions on checking pragmas,
subject only to the requirement that pragma Unsuppress shall allow any check
names supported by pragma Suppress. An implementation is allowed to add
additional check names, with implementation-defined semantics.  When
Overflow_Check has been suppressed, an implementation may also suppress an
unspecified subset of the Range_Checks.


                            Implementation Advice

28  The implementation should minimize the code executed for checks that
have been suppressed.

      NOTES

29  There is no guarantee that a suppressed check is actually removed; hence
a pragma Suppress should be used only for efficiency reasons.

29.1 It is possible to give both a pragma Suppress and Unsuppress for the
same check in the same declarative region. In that case, the last pragma
given determines whether or not the check is suppressed. Similarly, it is
possible to resuppress a check which has been unsuppressed by giving a
pragma Suppress in an inner declarative region.


J.X Specific Suppression of Checks

0.1 Checking pragmas can be used to suppress checks on specific entities.

                Syntax

0.2 The forms of specific checking pragmas are as follows:

0.3      pragma Suppress(identifier, [On =>] name);
          pragma Unsuppress(identifier, [On =>] name);

                               Legality Rules

0.4 The identifier shall be the name of a check (see 11.5). The name shall
statically denote some entity.

0.5 For a specific checking pragma that is immediately within a
package_specification, the name shall denote an entity (or several
overloaded subprograms) declared immediately within the
package_specification.

                              Static Semantics

0.6 A specific checking pragma applies to the named check from the place of
the pragma to the end of the innermost enclosing declarative region, or, if
the pragma is given in a package_specification, to the end of the scope of
the named entity. The pragma applies only to the named entity, or, for a
subtype, on objects and values of its type. A specific pragma Suppress
suppresses the named check for any entities to which it applies (see 11.5).
The meaning of a specific pragma Unsuppress is implementation-defined.

                         Implementation Permissions

0.7 An implementation is allowed to place restrictions on specific checking
pragmas.

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

From the minutes of the Columbia ARG meeting (November 17-19, 2000):

Randy summarized the changes since the April 2000 meeting:

 Make the second parameter obsolescent because the semantics of this construct
  is poorly defined and apparently rarely used (UK reports that in 4000
  instances of the Suppress pragma in 700K lines of code, there were only five
  uses of the second parameter). As an example of how poorly this feature is
  currently defined, Randy points out that it is not clear that the need to
  suppress the constraint check on the value of the expression to be assigned
  to an object can be done with the syntax ON => object.   Furthermore, Randy
  stated that under these circumstances Unsuppress (_, On => _) is impossible
  to define.
 Remove the symmetry between Suppress and Unsuppress with respect to
  inheritance, namely, unlike Suppress, Unsuppress is not inherited in package
  body or subunit.
 Leave the meaning of Suppress and Unsuppress as configuration pragmas
  implementation-defined.

On point 1, it was recommended that there is no need to explicitly mention an
obsolescence of the second parameter with the Unsuppress pragma in Annex J.
Instead there should be an Implementation Permission that allows
implementations to define and provide this feature. Also, a reference to the
new alternative features in 11.5 should be made in the first paragraph of the
addition to J.

Tuck wanted an additional wording to say that the checks that are (un)suppressed are not defined by the standard.

On point 2, it is very surprising that, without inheritance, in this example

package body P is
   pragma Suppress (all_checks);
   pragma Unsuppress (tag_checks);
   _
   procedure blah is separate;_
end P;

tag_checks are suppressed in blah depending on whether blah is "inlined" into the package or separate.  One question is whether the pragmas' treatment of inheritance should be symmetric.  The second question is whether inheritance should be permitted at al
l.  Arguments for safety state that there be no inheritance but many implementations do already implement Suppress inheritance.  Randy pointed out that implementations vary on how this is provided.

Tuck presented the case for limiting inheritance by saying that a configuration pragma overrides an inherited pragma and that the configuration pragma is overridden when an explicit pragma is specified.  If a unit wants to ensure that it has the checks the
n the pragma Unsuppress must be explicitly specified and it won't be sabotaged by a configuration pragma.  This appears to safely introduce Unsuppress with no changes to implementation regarding inheritance.  While this appears to be a reasonable approach,
 it wasn't selling at the meeting, because the rules seemed overly complicated and because of the example above.

Tuck then tried a different approach, by starting with checking for possible agreement on any of the following points:

 Unsuppress revokes Suppress permission, including inheritance, namely, revocation overrides inheritance.
 Configuration pragmas override inheritance (of Suppress) pragma.
 A (Un)Suppress pragma inside a compilation unit revokes the opposite effect by inheritance or configuration pragmas.
 Drop inheritance requirement.

There seemed to be agreement on point 1 and 3, less agreement on point 4 but no convergence on point 2.

Erhard tried to sell the case for eliminating inheritance as the "safest" approach until a better one is proposed.  Unfortunately, this approach is not upward compatible.

Tuck suggested four approaches to resolving this, as a way to get convergence:
 Require inheritance with weak configuration pragma (which is upward compatible)
 No inheritance, with configuration pragmas as starting point
 Inheritance is implementation-defined and configuration pragmas override inheritance (which is upward compatible)
 No configuration pragmas
Unfortunately this did not produce convergence either and the issue was tabled to let everyone sleep on it.

The next morning Tuck offered another view regarding the effect of inheritance and configuration with respect to these pragmas: Consider that Suppress pragma provides a set of permissions.  A configuration Suppress provides an initial set of permissions to
 be applied to a compilation unit.  The appearance of a Suppress pragma for a specific check in a compilation unit will add to the set of permissions for that compilation unit if the permission had not already been provided.  The appearance of a Unsuppress
 pragma for a specific check  in a compilation unit will revoke any permission to suppress that check for that compilation unit.  It appeared that this insight was quietly received.

Randy will revise this AI accordingly.

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

From: Randy Brukardt
Sent: Wednesday, February  6, 2002 at  6:05 PM

[In relation to Unchecked_Union (see AI-216); the semantic model is that
checks are suppressed. Unsuppress must not unsuppress those checks.]

> To me, the compelling advantage of this approach is its simplicity; only
> one line of RM text is needed because it uses an existing language mechanism.

Except that it messes up Unsuppress further; as the one with that short straw,
I'm not amused :-)

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

From: Robert Dewar
Sent: Wednesday, February  6, 2002 at  7:30 PM

You just say that Unsuppress unsupresses checks previously suppressed by
Suppress, then that does not include the unchecked union stuff.

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

From: Randy Brukardt
Sent: Wednesday, February  6, 2002 at  7:44 PM

Humm, that probably works. (Assuming we can ever figure out what Suppress does
- but let's not go there now. :-)

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

[Editor's notes, June 13, 2002]

Wording changes:
-- Removed specific Unsuppress from Annex J; added an implementation
   permission to allow supporting it.
-- Added a note in Annex J pointing at the implementation permission.
-- Added a sentence in Annex J to point out that the exact checks
   suppressed by a specific Suppress pragma are not defined by the standard.
   (That is, the language does not try to define whether the subtype check
    on assignment to A in A := B belongs to A, to B, or to both.)

-- Unsuppress now revokes the permissions to suppress given by a pragma
   Suppress only. This change is necessary to allow Unchecked_Union to
   use suppression semantics; Unsuppress must not have an effect on
   Unchecked_Union.

-- The region to which a configuration pragma Suppress applies is changed to
   be implementation-defined, but it must at least include the units to
   which it applies (by the rules of 10.1.5(8)).
-- The region to which pragma Unsuppress applies is changed to be the same
   as Suppress. (This means that Unsuppress inherits into bodies and subunits,
   as Suppress already does).

The discussion has been updated to reflect the above.

Why:

The first three changes were requested at the November 2000 meeting.

The fourth change is to reconcile with the "Suppress" semantics of
Unchecked_Union. Unsuppress must not have an effect on that. This wording
unfortunately suggests that explicit Unsuppresses should not override
compiler options (which may not be modeled in terms of Suppress). But there
doesn't seem to be a choice assuming the Unchecked_Union continues to use
suppression semantics.

The rest of the changes come from an analysis of the issues on which we were
stuck at the November 2000 meeting. Here is the analysis.

First, inheritance of pragmas inside of units (not configuration pragmas).
There are three choices:

1) Both Suppress and Unsuppress inherit into bodies and subunits.
2) Suppress inherits, Unsuppress does not.
3) Neither Suppress nor Unsuppress inherits.
4) The region that Suppress and Unsuppress apply to is implementation-defined,
   but it is at least the current declarative part or package specification.

The main case for inheritance is that, in an example like:

package body P is
   pragma Suppress (All_Checks);
   pragma Unsuppress (Tag_Checks);
   procedure Blah is separate;
end P;

Tag_Checks are suppressed in Blah depending on whether Blah is "inlined" into
the package or separate.

This problem occurs for both (2) and (3) (in slightly different ways), a point
for (1). We can't tell if the problem occurs for (4), as it depends on the
implementation, so no point is awarded.

On the other hand, safety suggests that Suppress and Unsuppress should be
explicit. That suggests that there should be no inheritance, a point for (3).
Again, no point for (4), since the language definition is not safe, although
a particular implementation can be.

Since Ada 83 and Ada 95 do have Suppress inheritance, (3) is incompatible with
the current standard. That is a point for each of the others (one presumes that
implementations would not change their implementations for (4)).

However, many compilers do not inherit Suppress, but some do.
(Note again that it is OK to ignore Suppress inheritance, because it is always
OK to ignore the permission to omit a check; but it is not OK to ignore
Unsuppress inheritance.) This could be considered a negative for (1), but
remember that compilers that do inherit Suppress would have to change for (3).
In addition, (2) would require two different mechanisms for the two pragmas.
It is unlikely that any existing compiler supports both currently, so that
is a negative for (2) as well. Moreover, this is a new feature, so some work
in implementing it should be expected. Thus we award 1/2 point to
(4) as it does not require changes in the existing Suppress implementation
nor a new mechanism for Unsuppress.

Totalling up the scores in the rather crazy assumption that these factors
should be given equal weight, we see that (1) has two points, (2) and (2)
have one point each, and (4) has one and 1/2 points. Therefore (1) is selected.
(It is annoying that safety is the point that loses out here, but this seems to
be the necessary conclusion, as it is true of the two highest scoring options.)
Note that (1) has the additional advantage of having the simplest model (the
same as the existing standard's model).

Having selected full inheritance as the model, we now turn to configuration
pragmas.

We have (at least) the following options:

1) Checking pragmas as configuration pragmas are implementation-defined.
2) Configuration pragmas inherit in the same way as pragmas inside a unit, and
   are essentially equivalent to putting the pragma at the very beginning of
   each unit to which it applies.
3) Configuration pragmas never inherit, but otherwise are equivalent to putting
   the pragma at the very beginning of each unit to which it applies.

Other options are rendered moot by the adoption of inheritance everywhere for
'regular' pragmas.

For all of these options, the configuration pragma (and any inheritance) can
be overridden by an explicit pragma inside the unit. This is clearly an
important property.

The definition of (3) seems too gruesome for words (or wording), as it involves
different regions of effect for configuration and regular pragmas. It also may
be hard for compilers to implement, especially those that currently do support
inheritance.

Thus the choice boils down to whether it is important to specify the region of
effect for configuration pragmas, or whether "implementation-defined" is good
enough. It should be noted that the explicit use of pragma Suppress and
Unsuppress as configuration pragmas is rare. Rather these pragmas as
configuration pragmas are usually used as compiler options. Compiler options
are implementation-defined, so it doesn't seem bad to make these pragmas
implementation-defined also. In particular, in the example above, no one would
be surprised if the checking in Blah differs from the checking in P if the
compiler options were different. So forcing inheritance of pragmas seems to
have much less value here than it does in the explicit pragma case. Indeed,
users probably would be surprised if the compiler option from P did
inherit into Blah.

The author finds this argument compelling. He hopes that the full ARG agrees.

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

[Editor's notes, January 14, 2003]

Wording changes:
-- Adjusted problem example as suggested at Bedford meeting;
-- Split wording of 11.5(8.1) into two sentences;
-- Clarified the wording of the second sentence of 11.5(8);
-- Added an AARM note to the static semantics section of J.XX.

I did not follow Tucker's suggestion from the meeting for 11.5(8.1). From the
minutes:

Tucker suggests changing the bracketed text to say if a Suppress pragma applies
to the instance body or inlined copy, the unrevoked permissions also apply to
the instance body or inlined copy. Or perhaps make it "unspecified" (we don't
want to force documentation of this, so it can't be implementation-defined).

This change would be wrong; we need to say that the Unsuppress pragma applies
there as well. I did add an AARM note to this effect, to clarify the intent
for future generations of implementers.

There are two unrelated issues here: the region to which an Unsuppress pragma
revokes permissions, and exactly what permissions are revoked. The original
wording rather confused those issues, as it isn't particularly important for
permissions to be precise. (If the permission is not used, that is the same
as the permission being ignored, which is always OK). For Unsuppress, the rules
are different: the checks whose permissions are revoked are only those in effect
at the point of the pragma. The region over which the permissions are revoked
are the same as for Suppress.

Thus, I've retained the checking pragma wording for the "region" portion of
definition. We definitely want the regions of application to be identical for
Suppress and Unsuppress, so we want to share that wording. OTOH, we use
special wording for Unsuppress to specify which permissions are revoked.

Since we are using the checking pragma wording for regions, it is important
that those regions include instances and inlined bodies.

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


Questions? Ask the ACAA Technical Agent