!standard 11.5(1-8) 00-03-23 AI95-00224/03 !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, 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. !proposal A new pragma Unsuppress is defined. pragma Unsuppress (identifier [, [On =>] name]); The identifier argument of Unsuppress is the same as Suppress. Unsuppress can be used in the same places as Suppress, with the same 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 Suppress 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): The forms of checking pragmas are as follows: pragma Suppress(identifier [, [On =>] name]); pragma Unsuppress(identifier [, [On =>] name]); 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(7) to apply to checking pragmas: For a checking pragma that is immediately within a package_specification and includes a name, the name shall denote an entity (or several overloaded subprograms) declared immediately within the package_specification. Change 11.5(8) to define the meaning of pragma UnSuppress: A 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 and includes a name, to the end of the scope of the named entity. If the pragma includes a name, the pragma applies only to the named entity, or, for a subtype, on objects and values of its type. Otherwise, the pragma applies to all entities. 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. 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. Add after 11.5(27): If more than one checking pragma which apply to the same check are given as configuration pragmas in different compilations, it is implementation-defined whether the check is suppressed. If an implementation supports the On parameter to pragma Unsuppress, the exact entities for which an Unsuppress pragma with an On parmameter revokes a check are implementation-defined. [In particular, whether checks suppressed with a general pragma Suppress (one without an On parameter) are revoked 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 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. !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. 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. Both pragmas Suppress and Unsuppress can be used as configuration pragmas. While it may it may seems that Unsuppress would be useless as a configuration pragma, it can be useful in conjunction with a Suppress pragma. For instance, the following pragmas would suppress all checks except storage checks in the entire program: pragma Suppress (All_Checks); pragma Unsuppress (Storage_Check); The exact meaning of a checking pragma when there is more than one in a particular declarative region depends on the order that it is given in. For example, reversing the order of the pragmas in the above example would simply suppress all checks. This poses a problem for configuration pragmas, though, as the order of configuration pragmas depends on the compilation model of the implementation. Of course, pragmas given in a single compilation have a well-defined order, so this gives us a solution which both allows the portable use of the pragmas without adding implementation burden. That is, we say that the meaning of conflicting checking pragmas given as configuration pragmas is implementation-defined unless the pragmas are given in the same compilation. Restrictions can be placed on pragma Unsuppress. This is necessary to avoid burdening implementations. For instance, some implementations cannot support fine-grained suppression of single objects, and we don't want to start requiring that. 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. The entities which have their checks revoked by an Unsuppress pragma with an On parameter are implementation-defined. This is necessary both because it is impossible to tightly define the meaning of Suppress and for implementation reasons. One issue is that 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. There is also an implementation issue. Implementations typically use a set of flags for non-specific Suppress pragmas (those without On parameters), and flags on individual entities for Suppress pragmas with On parameters. However, if something like pragma Suppress (Index_Check); ... pragma Unsuppress (Index_Check, On => A); occurs, the implementation would need to support "Suppress all index checks except those on A". Doing so would require either getting rid of the set of non-specific flags (using only the entity flags, which would make non-specific Suppresses quite expensive, as the entire symbolable would need to be walked when the suppression state changed), or implementing some sort of exception list. This implementation burden is not worth it for a capability whose meaning is implementation-defined anyway. Notice that the inverse case does not suffer from either of these problems. If a non-specific Unsuppress revokes a check on a specific entity, there is no gray area as to whether the check is performed or not. For example, in pragma Suppress (Access_Check, On => Some_Subtype); ... Obj : Some_Subtype; pragma Unsuppress (Access_Check); ...Obj.all... it does not matter if the check is made on Obj or on Some_Subtype, because we know the check will be performed. Alternative rules would likely be a surprise to users. If a user writes pragma Unsuppress (All_Checks); in some scope, they would be very surprised to discover that any checks are still suppressed. Moreover, if there were any checks still suppressed, the value of pragma Unsuppress as a portable preventative pragma is weakened: whether or not the program works may depend on the compiler used. Finally, the implementation of the revokation of specific checks is not difficult. It only requires that some way exist to find all of the entities which have had a pragma Suppress with an On parameter applied to them. A list would be appropriate, as the number of such entities will usually be small. At the application of a pragma Unsuppress, the list would be checked, flags changed on any entities that need it, and the changes stacked in the same way that local Suppress pragmas are handled. Unlike a Unsuppress pragma with an On parameter, no changes to the flags or added exception lists are needed. One minor surprise with checking pragmas is that an inherited pragma can override an explicitly given one. Checking pragmas are inherited into the bodies of packages when they are given in a specification. For example: package My_Pack is pragma Unsuppress (Access_Check); end My_Pack; pragma Suppress (Access_Check); package body My_Pack is -- pragma Unsuppress (Access_Check) inherited here. -- Access_Checks are not suppressed in this body. end My_Pack; Since the configuration pragma is outside of the package body, it is revoked by the inner, inherited Unsuppress pragma. While this may be momentarily surprising, it follows from the standard scoping rules. This case is more common than appears at first glance, as configuration pragmas can occur from compiler options. In the case given in the example, the result is probably what we want -- we do not want checks to disappear because of a compiler switch if there is an explicit Unsuppress somewhere. Unsuppress configuration pragmas will be rare, as they usually don't have any Suppresses to revoke. Thus, we don't need to consider its impact here. Since there is no clear advantage to a special rule to cover inherited pragmas, we simply use the natural interpretation. 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 (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. !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. *************************************************************