!standard 11.5(1-8) 03-01-14 AI95-00224/07 !standard 11.5(27) !class amendment 99-11-19 !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 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 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 given by any pragma Suppress that applies at the 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 Suppress pragma 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. !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 <> 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 <> 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 <> 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 <> 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 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 <> 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 ; 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 < 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 <> 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 <> 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: > > < 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 <> 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. <> 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 <> 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 > < 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 <> 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. <> 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 <> Seems reasonable to me ... < (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). <> 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 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 <> 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. > < 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 < 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 <> 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 > < 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 <> 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 <" 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 <> 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 <> 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 <> 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 <> 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 <> 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 <> 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: > > < 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 <> 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. <> 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 <> 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 <> 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: > ... > < 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 <> 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 <> 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 <> 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. <> 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 all. 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 then 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. ************************************************************