!standard C.8(01) 03-07-22 AC95-00058/01 !class amendment 03-07-22 !status received no action 03-07-22 !status received 03-04-14 !subject Pragma Unreferenced !summary !appendix From: Martin Dowie Sent: Monday, April 14, 2003 6:56 AM I've been making use of the GNAT specific pragma "Unreferenced" recently. For those who haven't used it it simply indicates to the compiler that while an entity is declared is not expected to be used. e.g. procedure Foo (I : Integer) is pragma Unreferenced (I); begin Put_Line ("Called Foo"); -- No reference to "I" end Foo; During compilation no warning is then given about the parameter "I" not being referenced within "Foo". Conversly if "Foo" is altered such that "I" *is* then but the pragma not removed then another warning is issued. This is not limited to parameters but to any entity. Unused parameters can be quite common in test stubs and also in callback routines and searching through build listings to spot the expected 'not referenced' from the real errors can be time consuming and error prone. This looks to me to be a candidate for making standard. Any thoughts? **************************************************************** From: Tucker Taft Sent: Monday, April 14, 2003 3:22 PM I would agree this sounds like a useful and simple pragma, that will enhance static detection of errors. **************************************************************** From: Nick Roberts Sent: Monday, April 14, 2003 4:02 PM I agree this pragma would be very useful and should be added at the next revision. **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 3:38 AM As it is often said that a poor proposal is better than no proposal, I offer this effort. The one thing that struck me was when looking through the ARM, I couldn't see any other similar pragma - one that acts on objects and subprograms and, perhaps more importantly, deals with *warnings*, so I have left the heading number and placement to the ARG (should it be approved). Also, I wasn't entirely sure whether point 5 should be placed under Legality Rules or some other section. !standard L !subject pragma Unreferenced !summary A standard "unreferenced" pragma is proposed which takes one or more, local_names as parameters. This pragma indicates that each of the local_name is not expected to be referenced within the current scope. !problem It is common for test stub subprograms and for callbacks not to use all the parameters passed to them. This pragma allows the programmer to specifically indicate that they do not expect an entity to be referenced within the subprogram. !proposal The form of the pragma Unreferenced is as follows: pragma Unreferenced(local_name {,local_name}); A pragma Unreferenced is only allowed in a declarative_part. The local_name of a pragma Unreferenced shall resolve to either a subprogram name or an object_declaration. !wording Insert section: A.B.C Pragma Unreferenced An occurrence of a pragma Unreferenced identifies a set of subprograms or objects which are declared but intentionally unused. The purpose of such a pragma is to help identify entities that are declared and intended to be used but are erroneously not referenced. Syntax The form of a pragma Unreferenced is as follows: pragma Unreferenced(local_name {, local_name}); Legality Rules 4 A pragma Unreferenced is only allowed within a declarative_part. Each local_name shall statically denote the declaration of an object or subprogram. 5 If local_name identifies more than one matching homonym in the current scope, then the entity most recently declared is the one to which the pragma applies. Static Semantics 6 A pragma Unreferenced indicates to an implementation that the entity is deliberately not referenced within the current scope. Dynamic Semantics 7 Execution of a pragma Unreferenced has no effect. Insert into Annex L replacing <> with the appropriate cross reference: pragma Unreferenced(local_name {,local_name}); -- !discussion This AI attempts to standardize the Unreferenced pragma already supported by various implementations. !example procedure Log (I : Integer) is pragma Unreferenced (I); begin Put_Line ("Test stub for Log called"); end Log; **************************************************************** From: Jean-Pierre Rosen Sent: Tuesday, April 15, 2003 4:22 AM > Legality Rules I would add: It is illegal to reference an entity denoted by a pragma Unreferenced. **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 4:59 AM >I would add: >It is illegal to reference an entity denoted by a pragma Unreferenced. Does the word 'illegal' imply an error should be raised rather than a warning (as currently implemented by GNAT)? **************************************************************** From: Jean-Pierre Rosen Sent: Tuesday, April 15, 2003 7:58 AM Definitely. See the definition of "illegal" in the RM ;-) BTW: it is not only useful, it is the only way you can write a test for it... **************************************************************** From: Tucker Taft Sent: Tuesday, April 15, 2003 8:33 AM Illegal means a compile-time error (not "raised" at run-time and not a warning). If you explicitly insert such a pragma, I believe a violation of the pragma should be considered an error. I realize it is just a warning in GNAT now, but I don't think we want to standardize that behavior. Chances are, someone who has gone to the trouble of using pragma Unreferenced with GNAT is probably also activitating the "warnings are errors" flag as well, so I don't think there are a lot of folks out there who would be annoyed if this became an error, rather than a warning. **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 9:10 AM Ok - I just had it in my mind that existing behaviour is probably easier to be agreed on. But an error suites me fine. I guess there is always the arguement that they should have been aware that they were using a non-portable feature anyway. **************************************************************** From: Tucker Taft Sent: Tuesday, April 15, 2003 4:49 AM Thanks for writing this up. What happens if there are subunit stubs ("... is separate;") within the scope of an entity having a pragma Unreferenced? Does the implied restriction on reference apply to the corresponding subunits? (I presume it does.) I would think it would be *illegal* to reference an entity named in a pragma Unreferenced. I see no reason to make it only a warning. On the other hand, the implementation might have a warning when it detects an entity is never referenced. Presumably this pragma suppresses that warning for the named entity. Such a warning will be trickier to implement in the presence of subunit stubs, unless all subunits are "inlined" at the point of the stub (which I believe they are in GNAT). Also, does the current GNAT implementation make pragma Unreferenced apply to the nearest overloading, or to all overloadings of the given name? If it only applies to the nearest overloading, then I would say the pragma must follow immediately after the declaration of the overloadable if there is more than one overloading. Otherwise, it is a maintenance headache. **************************************************************** From: Tucker Taft Sent: Tuesday, April 15, 2003 4:52 AM One other question -- this might be useful for names mentioned in "with" clauses. But local_name disallows that. Does GNAT have any way of specifiying that a with clause is intended to be unused? **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 5:41 AM It is also required to be in a declarative_part. No, GNAT doesn't have a such a feature nor does it actually give a warning if there is such an unused unit. We could always change the proposal to use 'direct_name'(?) instead of 'local_name'. direct_name would also allow a user defined operator to be unreferenced, yes? **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 5:21 AM >Also, does the current GNAT implementation make pragma Unreferenced >apply to the nearest overloading, or to all overloadings >of the given name? If it only applies to the nearest overloading, >then I would say the pragma must follow immediately after >the declaration of the overloadable if there is more >than one overloading. Otherwise, it is a maintenance >headache. Doesn't this section cover the above point? >> Legality Rules >> [snip] >> 5 If local_name identifies more than one matching homonym in the current >> scope, then the entity most recently declared is the one to which the pragma applies. **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 5:33 AM >Thanks for writing this up. You're welcome. I can now appreciate how difficult this all is - this has to come under the 'Easy' classification but it made me sweat! :-) >What happens if there are subunit stubs ("... is separate;") >within the scope of an entity having a pragma Unreferenced? >Does the implied restriction on reference apply to the >corresponding subunits? (I presume it does.) > >I would think it would be *illegal* to reference >an entity named in a pragma Unreferenced. I see >no reason to make it only a warning. On the other >hand, the implementation might have a warning when >it detects an entity is never referenced. Presumably >this pragma suppresses that warning for the named >entity. Such a warning will be trickier to implement >in the presence of subunit stubs, unless all subunits >are "inlined" at the point of the stub (which I believe >they are in GNAT). ok - the following is what GNAT (3.15p) does: -- test_unreferenced.adb procedure Test_Unreferenced is C : Boolean := False; pragma Unreferenced (C); procedure Subunit_Stub (A : Integer; B : Float) is separate; pragma Unreferenced (Subunit_Stub); begin null; end Test_Unreferenced; -- test_unreferenced-subunit_stub.adb separate (Test_Unreferenced) procedure Subunit_Stub (A : Integer; B : Float) is pragma Unreferenced (A, B); begin C := True; end Subunit_Stub; And it correctly identifies: 'test_unreferenced-subunit_stub.adb:6:04: warning: pragma Unreferenced given for "C"' Does this require an extra 'Legality' rule? Or would this already be covered by the existing scoping rules? **************************************************************** From: Arnuad Charlet Sent: Tuesday, April 15, 2003 6:04 AM > No, GNAT doesn't have a such a feature nor does > it actually give a warning if there is such an > unused unit. Actually it does, when using -gnatwu The only way to turn off this particular warning is to use pragma Warnings (Off) as far as I know. **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 6:37 AM Apologies - I was thinking in terms of language exensions that would be 'half-inched' rather than compilation switches. I shall go and see if '-gnatwu' is worth adding to my list of de-facto GNAT swithes... **************************************************************** From: Stephane Barbey Sent: Tuesday, April 15, 2003 6:44 AM >One other question -- this might be useful >for names mentioned in "with" clauses. I would love it, as in with my_package_linker_options; pragma Unreferenced (my_package_linker_options); with my_package_elaboration_is_required; pragma Unreferenced (my_package_elaboration_is_required); Be aware that the pragma Warnings is not allowed in all organizations... We have to correct the source of warnings, not shut up the compiler... **************************************************************** From: Robert A. Duff Sent: Tuesday, April 15, 2003 11:56 AM I agree -- it sounds useful. Note that sometimes a parent package has a 'with' that is intended to be used by all of its children (the parent is often empty, even). GNAT warns about this case, even though the thing is referenced in the children. > Be aware that the pragma Warnings is not allowed in > all organizations... We have to correct the source of > warnings, not shut up the compiler... That sounds like an unreasonable policy, because it is better to have a pragma Warnings(Off) with a comment explaining why, than it is to have some bogus, useless, obfuscatory code inserted just to shut the compiler up. I don't think we need to perturb the language design for the benefit of unreasonable policies. (It's even better for compilers to avoid bogus warnings, of course, but that's not always feasible.) **************************************************************** From: Stephane Barbey Sent: Tuesday, April 15, 2003 12:54 PM > Note that sometimes a parent package has a > 'with' that is intended to be used by all of its children (the parent is > often empty, even). GNAT warns about this case, even though the thing > is referenced in the children. ... and that's the right thing to do. Otherwise you see things like: with Starlet; with Motif; with X; package GUI is end GUI; ... and then people complain why it does take so much time to compile that little child unit that actually just declare an exception. (If you want to be compiler-specific, Gnat even tells you that a with clause can be moved from the body to the spec, and does not consider renamings as references, i.e. in with Starlet; with Motif; with X; package GUI is package ST renames Starlet; end GUI; the unit Starlet still is a non-used unit -- which sounds like the right behaviour to me.) **************************************************************** From: Robert A Duff Sent: Tuesday, April 15, 2003 7:42 AM > Doesn't this section cover the above point? No, I think Tucker was asking for this: procedure Foo(...); procedure Foo(...); -- Pragma applies to this one. X: Integer; pragma Unreferenced(Foo); to be illegal, because another declaration intervenes between the pragma and what it applies to. The following wording does not seem to disallow the above: > >> Legality Rules > >> > [snip] > >> 5 If local_name identifies more than one matching homonym in the current scope, > >> then the entity most recently declared is the one to which the pragma applies. Unless you interpret that to mean that the above Unreferenced(Foo) refers to X (the "entity most recently declared"), which is surely not the intent! **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 8:10 AM Ah! I see what you mean now! :-) Would a change to: "...then the homonym most recently declared..." suffice? **************************************************************** From: Tucker Taft Sent: Tuesday, April 15, 2003 8:29 AM Not really. The point is that if you have this rule about a pragma applying to the most recently declared overloading, then from a maintenance point of view, it is important that there be no significant "gap" between the declaration of the overloading and the pragma. Otherwise, someone who doesn't notice the "distant" pragma Unreferenced may insert another overloading between the intended overloading and the pragma. This is what I mean by a "maintenance headache." **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 10:36 AM Is that really a problem? If there is a new overloading then: a) it is referenced - and referencing something (even accidentally) marked as 'pragma Unreferenced' would be an error; or b) it is unreferenced and the pragma works for it. But this leaves the first item unreferenced but without the protection of the 'pragma Unreferenced' so a compiler is free to do what it currently can do and point this out. Presumbly, the original 'pragma Unreferenced' was there to ensure that no such warning could be given - we're not making unreferenced entities (without the pragma) illegal. This pragma gives the biggest benefit when used with compilers that point out unreferenced entities anyway. So hopefully, those that don't would start to do so if implementing this pragma (Implementation advice? Tricky I guess...). **************************************************************** From: Arnaud Charlet Sent: Tuesday, April 15, 2003 8:36 AM > the "warnings are errors" flag as well, so I don't think there > are a lot of folks out there who would be annoyed if this > became an error, rather than a warning. Hopefully not, although you never know. Another issue while we're at studying GNAT semantics on this pragma: We also use this pragma to mark a variable as never read. In particular it means that if a variable is only modified, GNAT will be default issue a warning, and won't if pragma Unreferenced is specified. An example to clarify this: procedure F is Ignore : Boolean; -- pragma Unreferenced (Ignore); begin Ignore := Function_With_Side_Effect; end F; GNAT will generate a warning about Ignore being never read, unless you add a pragma Unreferenced (Ignore); **************************************************************** From: Martin Dowie Sent: Tuesday, April 15, 2003 9:32 AM >GNAT will generate a warning about Ignore being never read, unless you add a >pragma Unreferenced (Ignore); Personally, I'd rather see a different pragma for this use. Perhaps "pragma Write_Only"? I'm trying hard not to suggest "pragma Write_Only_Object". Object is just way too overloaded but perhaps in this case... **************************************************************** From: Robert A. Duff Sent: Tuesday, April 15, 2003 10:24 AM I don't really agree, but I suppose it's a matter of taste. But I must say, GNAT has precedence here; we should not be making gratuitous changes to what they have already implemented. I think the change that some have suggested, of making a certain warning into an error, is not gratuitous -- after all, GNAT really couldn't make it an error since it wasn't standard. And making it an error is a trivial change for GNAT, I trust. But I don't think it's a good idea to fiddle with the pragma names and so forth -- that would be disruptive to both GNAT implementers and users. **************************************************************** From: Tucker Taft Sent: Tuesday, April 15, 2003 12:41 AM Hmmmm, this isn't what I presumed "Unreferenced" meant. I think of "reference" as a general term meaning roughly the equivalent of "mention." It sounds like GNAT is interpreting it as meaning "read." I somewhat agree with Nick that using "Unreferenced" to mean "never read" sounds like a misnomer. **************************************************************** From: Nick Roberts Sent: Tuesday, April 15, 2003 10:25 AM I am currently writing up a new proposal. It will take me a few hours or a day. I hope it will address many of the issues regarding this pragma. I'd want to avoid duplication of effort, so if anyone else is doing the same thing, would they please say so (either to me directly nickroberts@blueyonder.co.uk) or to this mailing list. **************************************************************** From: Robert Eachus Sent: Tuesday, April 15, 2003 1:22 PM I like the idea of standardizing the pragma. On the issue of applying to the most recent homonym, I would prefer that it apply to all homonyms like pragma Inline, but I don't see it as a major issue. (In fact, I really feel that this issue is not worth all the electrons that have been spent on it so far. Applying the pragma to a locally declared subprogram is going to be rare, and to a locally overloaded subprogram rarer still.) With tongue firmly in cheek, and my Norm Cohen mask firmly in place, I will point out that we need to describe in the AI which attributes read (RM 3.3(14)) the object for the purposes of this pragma. Taking off the mask, I think that any use of the name of the object, subprogram, task or entry* as a prefix should be illegal. (This includes attributes, discriminants, array indices, record components, function return values, task entries, and so on.) There is a legality issue we do have to get right. In the case of a parameter or object declaration, if it is legal for the compiler not to materialize the object named in the pragma, is it also legal to eliminate initialization of the object? Some cases are trivial. A task object still needs to be created. To see one of the more painful possible cases think about a dynamically sized array of records where the calculation of the bounds may have side effects as may the default initial value for some field of the record. Note also that exceptions may be explicit or implicit side effects. I think the answer has to be that parameters, including out parameters must be initialized. Also, the pramga loses some of its usefulness if explicit initializations with side effects can be eliminated. I would like to see elimination of default initial values allowed, but I suspect that the possibility of task (sub)components would may any such rule too complex to be worth even proposing. *It would be nice to allow the pragma to be used within task bodies to indicate entries that are never accepted. Extending this to members of a family of entries, though, is definitely going out where the air is too rare to support the implementation effort. (I find it hard to conceive of cases where I would want to use the pragma with entry families, in fact, it is hard enough to conceive of uses for entry families.) **************************************************************** From: Stephen Leake Sent: Tuesday, April 15, 2003 1:48 PM I agree that "Unreferenced" is a misnomer for the GNAT implementation. I've been using "Unreferenced" since ACT introduced it, and did not realize it meant "unread" until now; on reading the description the first time, I thought it meant "no reads, no writes". On re-reading the GNAT manual, it does say assignment to an "Unreferenced" object is allowed: "The left hand side of an assignment does not count as a reference for the purpose of this pragma. Thus it is fine to assign to an entity for which pragma Unreferenced is given." I suspect this was added after the pragma was initially defined, to allow some special case. Apparently I have not needed a "no read, no write" pragma. In the light of Robert Eachus's comments about attributes and default initialization (all of which are important), it may not be possible to define a truly "no read, no write" pragma, so perhaps "Unread" is really what we want. I would not allow any initialization (implicit or explicit) to be optimized out; that is what most programmers will unconsciously expect. I think the having Unreferenced apply only to the most recent homonym is a mistake; it should act like "Inline". Having it inconsistent will cause inadvertant mistakes. If you want it to apply to only one subprogram, give it a unique name, and use renaming to get the overloaded name (just like for Inline). **************************************************************** From: Robert A. Duff Sent: Tuesday, April 15, 2003 2:18 PM Regarding Robert Eachus' comments about side-effecting initializations, my opinion is: pragma Unreferenced should have exactly zero semantic effect at run time. **************************************************************** From: Randy Brukardt Sent: Tuesday, April 15, 2003 2:50 PM I agree with that; we've already dealt with initializations in other AIs and I'd hate to reopen that discussion here. That said, I find this a very suspicious pragma: it's only useful effect is on warnings (I see no value at all to checking that something is in fact not used). And warnings are something that have no real standing in the RM. So we're supposed to add a pragma with no use that we can describe in RM terms? I'm also very suspicious of the GNAT definition that Unreferenced means Unread. That would be a relatively difficult check to make in Janus/Ada, since there is no practical difference between reading and writing of an object -- all tree nodes look alike. To determine whether something is written would require determining where in the tree it appears, which is neither trivial nor desirable. (Unreferenced is much easier, as it applies to all tree nodes.) In my experience, most of things that GNAT complains about are 'in out' parameters that are unwritten. That happens a lot, because Ada doesn't give us any way to have default values for 'out' parameters (which these really are supposed to be), and it is common that they are not used in some cases. Moreover, the message is not really helpful (nor is suppressing it helpful), because what you really need to know is whether the parameter is ignored because the parameters say that it is not meaningful, or whether it was omitted. That requires a more complex condition than any standardized pragma can give. So I'm against standardizing this pragma. Its value is for things outside what the RM can talk about usefully, so I don't think it belongs in the RM. (Unless you want to define it to be to have unreferenced objects otherwise, but I think that is too big a change.) **************************************************************** From: Alexandre E. Kopilovitch Sent: Tuesday, April 15, 2003 5:37 PM I'd like to note that here are two kinds of references involved: a reference to a variable (or identifier) and a reference to the value of a variable. GNAT's pragma "Unreferenced" is (as it appears) for the latter case, and perhaps the name "Unreferenced_Value" would be more appropriate for it. Although, it is still unclear for me what does this pragma mean for a variable of controlled type, where an assignment may involve reading of the value. **************************************************************** From: Robert I. Eachus Sent: Tuesday, April 15, 2003 7:14 PM It is becoming increasingly clear to me that if we have a standard pragma Unreferenced, it should mean that the NAME is not used after the (full) declaration. This means that: ... Junk: Integer := Foo(X); pragma Unreferenced(Junk); ... is legal and easy to Understand, while: X: String := Some_Complex_Function; pragma Unreferenced(X); ... if X'First /= 1 then... is clearly illegal. One final detail. I am not sure that we want to leave the class of things to which pragma Unreferenced can apply unstandardized, or what the limits should be. In any case, if pragma Unreferenced is added to the standard, then all the names listed in the pragma must be legal and correspond to one or more entities. Complicated sounding, but what it really comes down to is that the author expects an error if a pragma Unreferenced fails. As far as the author is concerned, a spelling error is just as bad as any other failure. So silently ignoring invalid names in a pragma Unreferenced would be bad juju: procedure Foo(Some_Long_Variable_Name: in Integer); pragma Unreferenced(Some_Long_Varaible_Name); begin ...if Some_Long_Variable_Name /= 0 then... end Foo; This case must cause some sort of error... **************************************************************** From: Martin Dowie Sent: Wednesday, April 16, 2003 2:50 AM >procedure Foo(Some_Long_Variable_Name: in Integer); >pragma Unreferenced(Some_Long_Varaible_Name); Here is another case for insisting that the pragma follow immediately, as there could very well be an entity in scope called "Some_Long_Varaible_Name". I'm rapidly coming to the conclusion that if this pragma is to be included it should have a different name and not try to mimic exactly the GNAT semantics. How about "pragma Not_Referenced"? The semantics should be, in Tucker's words "not mentioned" - not reading, no attributes and no semantic effect at runtime. If adding entries to this list would be deemed expensive to implement, I'd be happy to leave its effect limited to: 1) parameters 2) objects 3) subprograms 4) units in context clauses I could possibly even live without 4) - the benefit to this is going to >95% of the time with item 1). Actually, I could even live with item 1) being the only entity that this pragma dealt with - "pragma Unused_Parameter" - it might even make it feasible to define a set of rules that work! :-). I have used this sort of rule in another language before and it *was* used and did prove useful then. **************************************************************** From: Nick Roberts Sent: Tuesday, April 15, 2003 5:47 PM ----- Original Message ----- From: > As it is often said that a poor proposal is better than no proposal, I > offer this effort. I can only apologise myself for my manifest ineptitude at making (various) proposals. I think the proposal Martin made would have to be elaborated upon a little. I suspect a new section would need to be added to the RM regarding warnings for 'abnormally used' entities. I think it would be advantageous for such a section to be added, but I guess Randy would disagree. > The one thing that struck me was when looking through the ARM, I couldn't > see any other similar pragma - one that acts on objects and subprograms > and, perhaps more importantly, deals with *warnings*, so I have left the > heading number and placement to the ARG (should it be approved). Similarly, I've not attempted any numbering related to the current RM. I have changed the name of the pragma (from "Unreferenced", which GNAT currently uses). I believe the disruption caused by this to the implementation of GNAT would be minimal, and the disruption to GNAT users would be none at all if GNAT were simply to retain implementation of the pragma Unreferenced (as a synonym for Abnormal_Usage). I have avoided extending the pragma to apply to library units mentioned in a the context clause of a unit but never used inside the unit, because the simpler solution to getting spurious warnings from doing this is to comment out the (relevant part of the) context clause until it is needed. What I present here is not complete. I thought perhaps it would be better to post it as it is now, in the light of the fact that it may well be rejected anyway :-( It should not be taken as a fait accomplis, but only a starting point for much further refinement. !standard L !subject pragma Abnormal_Usage (was Unreferenced) !summary This AI proposes: * a section is added to the RM giving guidance on warnings to be given for abnormally used entities; * a standard pragma is introduced, called Abnormal_Usage, which applies to the declaration of a view (of an entity), and indicates that the view is expected to be abnormally used. !problem During the sometimes lengthy process of the development of a software module it is common for the usage of views (of entities) declared within the module to be 'abnormal'. Abnormal usage, for example, might include a subprogram parameter which is never read or updated in the body of the subprogram. Compilers are likely to be programmed to give a warning about abnormal use, because of the suspicion that the abnormal use indicates an inadvertant error. Such warnings can be problematic in that they can occur in such profusion as to obfuscate other, more important, warnings. !proposal A section is added to the RM explaining when a compiler should give a warning about the abnormal usage of a view of an entity. The new section describes a new pragma, "Abnormal_Usage", which allows the programmer to indicate that an entity is expected to be abnormally used (for the time being). Compilers will be expected to suppress any abnormal use warning for any view which is so indicated, and to give a warning otherwise. The form of the pragma Abnormal_Usage is as follows: pragma Abnormal_Usage ( view_name {, view_name} ); In addition, compilers will be expected to produce a warning for any view indicated by this pragma but which is not, in fact, abnormally used (because of the suspicion that the pragma itself has been aberrantly applied or not deleted). !wording *** Insert section: A.B Usage Warnings and Pragma Abnormal_Usage An implementation shall provide a warning for every occurrence of a view of an entity that is 'abnormally used' unless that view is 'marked for abnormal use'. An implementation shall provide a warning for every occurrence of an view that is not abnormally used and is marked for abnormal use. A view is defined as abnormally used if it is not declared within the visible part of a library package, and: * it is not a library unit and there is no usage name of it within the scope of its declaration; * it is of an object which is not volatile, a loop parameter, or of a task or protected type, and whose value could not possibly be read by any execution of the program; * it is of a variable object which is not volatile or of a task or protected type and whose value could not possibly be updatde before being read by any execution of the program; * it is of an exception and there is no usage name of it in a raise statement; * it is of a callable entity and there is no usage name of it in a call; * [others?] A.B.C Pragma Abnormal_Usage An occurrence of a pragma Abnormal_Usage identifies an entity which is to be marked for abnormal use. Syntax view_name ::= direct_view_name | subprogram_parameter_name direct_view_name ::= identifier subprogram_parameter_name ::= subprogram_name . parameter_name subprogram_name ::= identifier parameter_name ::= identifier The form of a pragma Abnormal_Usage is as follows: pragma Abnormal_Usage ( view_name {, view_name} ); Name Resolution Rules If the view name is a direct view name, it shall resolve to denote one or more declarations in the same declarative region as the pragma. If the view name is a subprogram parameter name, the subprogram name shall resolve to denote one or more subprogram declarations in the same declarative region as the pragma, and the parameter name shall resolve to denote one of the parameters of each such subprogram declaration which has a parameter of that name. [Several other kinds of view name could be added. For example, components of a record type declaration.] Legality Rules A pragma Abnormal_Usage is only allowed in a declarative region. If a view name is a subprogram parameter name, it must denote at least one subprogram parameter. Static Semantics A pragma Abnormal_Usage applies to the views which each view name applies to. If a view name is a direct view name it applies to the view of each declaration it denotes. If a view name is a subprogram parameter name, it applies to the subprogram parameters it denotes. Each view to which a pragma Abnormal_Usage applies is marked for abnormal use. Dynamic Semantics Abnormal_Usage has no effect other than those described above. Implementation Advice If an implementation is not able to determine whether a view is abnormally used, it should not consider the view to be abnormally used. Implementation Permissions An implementation is permitted to add further conditions under which a view is considered to be abnormally used. All such further conditions must be documented. The form of the warnings produced by an implementation is not defined by this standard. *** Insert into Annex L replacing with the appropriate cross reference: pragma Abnormal_Usage ( view_name {, view_name} )]; -- !discussion This AI attempts to standardize the Unreferenced pragma already supported by various implementations. !example procedure Log (I : Integer) is begin Put_Line ("Test stub for Log called"); end Log; pragma Abnormal_Usage (Log.I); **************************************************************** From: Tucker Taft Sent: Wednesday, April 16, 2003 11:39 AM I would suggest we avoid the term "referenced" completely, if we are going to change the name. How about: pragma Not_Used(local_name {, local_name}); and pragma Not_Read(local_name {, local_name}); The GNAT Unreferenced would be roughly equivalent to Not_Read, I presume. If we only want to standardize one, I would opt for Not_Used since I think that is (a) easier to define and (b) probably more useful. **************************************************************** From: Orville E. Wheeler Sent: Wednesday, April 16, 2003 11:49 AM Tucker Taft is right. It also has more intuitive appeal to me! **************************************************************** From: Robert A. Duff Sent: Wednesday, April 16, 2003 3:11 PM I do not agree. I think "never mentioned" and "never read" are roughly the same potential bug, and I think only one pragma is in order. I think Not_Read is a superset of Not_Used, and both are "questionable", deserving of warning, and deserving of a pragma to turn off the warning. I don't much like the name "Unreferenced", but I think GNAT has precedence -- the whole point of this discussion is to standardize something already implemented by that compiler. To redesign the feature, for gratuitous reasons, defeats the purpose. Unless the GNAT semantics are seriously broken, or ill defined, the ARG should just take it or leave it as is -- not fiddle with it. Look: X: Integer; Y: Integer := ...; Z: Integer; ... Z := ...; You want me to use two different pragmas for X and Y and Z (if they are not mentioned again)?! Think from the user's point of view, here, not the compiler writer's. Maybe somebody from ACT can post RM-ish wording that exactly matches what GNAT actually does. The wording from GNAT's manual is not up to RM standards (e.g. it talks about the "entity most recently declared", which is of course nonsense: how is the compiler to know which declaration I typed in most recently! -- the RM talks about "places" in the source code). Then we can judge whether the GNAT semantics makes sense. If so, let's standardize it. If not, let's forget the whole thing. **************************************************************** From: Tucker Taft Sent: Wednesday, April 16, 2003 3:55 PM > I do not agree. I think "never mentioned" and "never read" are roughly > the same potential bug, and I think only one pragma is in order. I > think Not_Read is a superset of Not_Used, and both are "questionable", > deserving of warning, and deserving of a pragma to turn off the warning. > I don't much like the name "Unreferenced", but I think GNAT has > precedence -- the whole point of this discussion is to standardize > something already implemented by that compiler. To redesign the > feature, for gratuitous reasons, defeats the purpose. The reasons for changing the name don't seem gratuitous, given the number of messages this has generated. I agree it would be ideal to standardize an existing pragma, but it seems that it is sufficiently confusing that it would be better to pick a new name. As far as whether Not_Used or Not_Read is more useful, I agree it is hard to decide which is preferable. As mentioned above, getting the definition of "Not_Read" correct may be subtle, but I am willing to wait until someone from ACT takes a shot at it. On the other hand, I believe Not_Used would get you at least 95% of the benefit of Not_Read, and has a very simple definition (famous last words ;-). > Unless the GNAT semantics are seriously broken, or ill defined, the ARG > should just take it or leave it as is -- not fiddle with it. > > Look: > > X: Integer; > Y: Integer := ...; > Z: Integer; > ... > Z := ...; > > You want me to use two different pragmas for X and Y and Z (if they are > not mentioned again)?! Think from the user's point of view, here, not > the compiler writer's. If you really want something to use as a "dummy" target of an assignment, it seems simple enough to initialize it on declaration. I just think it will look weird to see: Z: Integer; pragma Unreferenced(Z); begin Z := ...; Such a use of the term "unreferenced" is counterintuitive to me. **************************************************************** From: Randy Rbukardt Sent: Wednesday, April 16, 2003 5:03 PM > Unless the GNAT semantics are seriously broken, or ill defined, the ARG > should just take it or leave it as is -- not fiddle with it. I asked Robert Dewar (privately, since he's not on this list) about this pragma and the discussion yesterday. I won't post his exact response (I don't post private mail publicly) but here's my paraphrase of it: 1) He agreed with my feeling (posted yesterday) that the pragma Unreferenced (which deals with warnings) is a poor candidate for standardization. (Well, he said 'rubbish' :-). 2) He thinks that making programs illegal by the use of this pragma is 'wildly misguided'. 3) ACT does not want to have to change their implementation, which they would need to do if we standardized something different than the current GNAT implementation. See (1) and (2). 4) They choose the way Unreferenced work for good reasons (which he didn't elaborate on), but he added that they're pragmatic reasons, as with all warnings. So, I think we need to change the name of this pragma (if we want to make this something we can say something useful about in the RM). Otherwise, I think we should drop the idea - if the designer of the pragma thinks its a bad idea, why should we claim to know better?? **************************************************************** From: Jean-Pierre Rosen Sent: Wednesday, April 16, 2003 12:18 PM > If adding entries to this list would be deemed expensive to > implement, I'd be happy to leave its effect limited to: > 1) parameters > 2) objects > 3) subprograms > 4) units in context clauses > > I could possibly even live without 4) - the benefit to this > is going to >95% of the time with item 1). Definitely NOT! Example: AWS. A web page is actually a package, whose initialisation code registers call-backs to the server. You must with these packages for them to be included in the application, but they are not otherwise used (the specification may well be empty). Other example: packages that start tasks. **************************************************************** From: Bernard Maudry Sent: Thursday, April 17, 2003 3:51 AM I really think that this is only needed for parameters so the pragma should be named Unused_Parameter. If the others are unused, removing them or commenting them out is the best solution. For with clauses, the fact that the indicated entity is unused (like Link_Options) is not to be warned unless the programmer explicitly asked for such a warning. **************************************************************** From: Robert A. Duff Sent: Thursday, April 17, 2003 2:37 PM A few days ago, I went through all the unused entities in a program of about 100,000 lines of code. There were about 500 cases. About half were with_clauses. Of those, about 50 were correct (i.e. there was good reason to with the thing and not refer to it). The rest were simply useless with_clauses -- harmless, except for cluttering the code, and increasing compile time. I didn't count the non-with_clause half carefully, but I guess about half of those were parameters and half were local variables. Almost all were legitimate. A couple of cases were actual bugs, something like this: procedure P(A: T1; B, C, D, E, F: T2 := Default); ... procedure Q(B, C, D, E, F: T2 := Default) is begin P(A => Something, B => B, C => C, D => D, E => E); -- wrong! end Q; where the intent was for Q to be a wrapper for P, filling in the A parameter, and passing all the rest along unchanged. But the F parameter is missing above, and therefore generated the "unused entity" warning. As to the legitimate cases, there were a few common reasons. A common technique is to declare an object of a Limited_Controlled type, purely for the purpose of running the Initialize and Finalize routines. There were also examples like "Ignore: constant T := F(...);" where the purpose is to call F for side effects and ignore the result. And there were cases where a formal parameter was required, because the procedure was overriding another procedure, or was being passed to a generic, so its profile had to match some other thing, but in this particular case, the procedure didn't want to look at its parameter. **************************************************************** From: Robert I. Eachus Sent: Thursday, April 17, 2003 5:53 PM >I really think that this is only needed for parameters so the pragma >should be named Unused_Parameter. I totally disagree. First unused parameters are one useful case, but there are several others of equal or greater weight. Second, even if it were limited to parameters, naming the pragma Unused_Parameter is an extreme case of lily guilding, since the name of the unused entity or entities will immediately follow. Having a pragma with a name like Not_Used or maybe even Unused would allow me to eliminate a number of non-meaningful junk names (usually Junk ;-) from my code. Robert A Duff wrote: > A few days ago, I went through all the unused entities in a program of > about 100,000 lines of code. There were about 500 cases. About half > were with_clauses. Of those, about 50 were correct (i.e. there was good > reason to with the thing and not refer to it). The rest were simply > useless with_clauses -- harmless, except for cluttering the code, > and increasing compile time. The with clause case is a major argument for a standard pragma. I know that the meaning is more like "not used here, but my children need it here for elaboration sequence reasons." But that is a little too long for even an Ada pragma name. But the real need for the pragma in the with clause case is that it allows a programmer to document a decision in a meaningful way. By having both the with clause and the pragma, he says that this isn't junk, there is a reason it is located here. Now a maintenance programmer coming along later won't introduce a bug by moving the with clause to what looks to him as a more appropriate location. (Usually from package specification to package body.) > I didn't count the non-with_clause half carefully, but I guess about > half of those were parameters and half were local variables. Almost all > were legitimate. A couple of cases were actual bugs, something like > this... Exactly. Five hundred warning messages are either never going to be checked, or checked only once. Cut that to three, and even if only two are errors, the errors will be found and fixed. > As to the legitimate cases, there were a few common reasons. A common > technique is to declare an object of a Limited_Controlled type, purely > for the purpose of running the Initialize and Finalize routines. > There were also examples like "Ignore: constant T := F(...);" > where the purpose is to call F for side effects and ignore the result. > And there were cases where a formal parameter was required, because > the procedure was overriding another procedure, or was being passed to a > generic, so its profile had to match some other thing, but in this > particular case, the procedure didn't want to look at its parameter. Yep, I run into the parameter formal matching case fairly often. But there is one case I ran into where NOT using the pragma would have saved a lot of trouble. The issue involved an AVL tree where normally look-ups were done using one key. But there were occasions where every entry had to be examined based on a secondary key--eliminating expired entries based on a date. I won't show the gory code here. {Lots of text eliminated by author here. Send e-mail if you really must know.} So what was the problem? A compiler warning that Current_Key might never be assigned a value. Since it was only set or read in nested subprograms, the warning was true, but gratuitous. Kludges to eliminate that warning got us into trouble on too many occasions. The final solution was a comment: Current_Key: Name; -- Do not touch. This especially means me. -- RIE **************************************************************** From: Martin Dowie Sent: Monday, April 21, 2003 4:24 AM Ok - here is a more limited version using the name 'Not_Used'. This proposal is currently limited to parameters. The only other area that I can see being of any real benefit would be usused context clauses. I may come back with an update that includes a rule for that, time permitting. I've avoided using 'Unused_Parameter' so that, as rule for other language features become available they can be added. ============================================================================ !standard L !subject pragma Not_Used !summary A standard "Not_Used" pragma is proposed which takes one or more, defining_identifier as parameters. This pragma indicates that each of the defining_identifier is not expected to be referenced within the current scope. !problem It is common for test stub subprograms and for callbacks not to use all the parameters passed to them. This pragma allows the programmer to specifically indicate that they do not expect an entity to be referenced within the subprogram. !proposal The form of the pragma Not_Used is as follows: pragma Not_Used(defining_identifier {,defining_identifier}); A pragma Not_Used is only allowed in a declarative_part. The defining_identifier of a pragma Not_Used shall resolve to a formal parameter. !wording Insert section: A.B.C Pragma Not_Used An occurrence of a pragma Not_Used identifies a set of defining_identifiers which are declared but intentionally unused. The purpose of such a pragma is to help identify formal parameters that are declared and not intended to be used but are erroneously referenced. Syntax The form of a pragma Not_Used is as follows: pragma Not_Used(defining_identifier {,defining_identifier}); Legality Rules 4 A pragma Not_Used is only allowed immediately within the declarative_part of a subprogram_body, prior to any declarative_item. 5 Each defining_identifier shall statically denote a formal parmeter. 6 It is illegal to reference a defining_identifier denoted by a pragma Not_Used. Static Semantics 7 A pragma Not_Used indicates to an implementation that the defining_identifier is deliberately not used within the current scope. Dynamic Semantics 8 Execution of a pragma Not_Used has no effect. Insert into Annex L replacing <> with the appropriate cross reference: pragma Not_Used(defining_identifier {,defining_identifier}); -- !discussion This AI attempts to standardize a Not_Used pragma that provides some of the benefits of an existing implemenation defined pragma. To avoid confusing with the existing implementation, the pragma name has been changed. !example procedure Log (I : Integer) is pragma Not_Used (I); -- Legal begin Put_Line ("Test stub for Log called"); end Log; procedure Log (I : Float) is V : Integer := Integer (I); pragma Not_Used (I); -- Illegal, pragma comes too late, "I" already used begin Put_Line ("Test stub for Log called"); end Log; **************************************************************** From: Robert A. Duff Sent: Monday, April 21, 2003 1:08 PM Well, I still say GNAT got it right (as far as I can tell -- I haven't seen a precise description of what GNAT does). The only complaint about the GNAT solution that I agree with is a mildly poor choice of name. But it's not *that* bad; it's certainly not worth "fixing" when many users already have it in their code. And, as far as I can tell, the semantics of all the proposed alternatives is inferior to that of GNAT's pragma. **************************************************************** From: Martin Dowie Sent: Monday, April 21, 2003 4:03 PM The only problem I have with the GNAT name is that it isn't obvious that you can actually referenced something marked as 'Unreferenced' - I think it came as a surprise to a few people on the list, judging by the subsequent comments! (As far as I can see, the user guide in the public version doesn't contain the 'full definition' that was quoted a few days ago). I'm sure ACT had good reason for making it so, but it seems to run counter to 'the principle of least surprises'. I've got another proposal that adds rules to allow with_clause checking, if it is felt that would be of benefit. I'm still not convinced about the need to cover variables/constants/subprograms/entries, but if someone wants to write up those rules, feel free! **************************************************************** From: Stephen Leake Sent: Tuesday, April 22, 2003 9:55 AM > (As far as I can see, the user guide in the public version doesn't > contain the 'full definition' that was quoted a few days ago). Here's the complete text from the GNAT 3.16a reference manual (GNAT 3.16a is a current ACT pre-release): --------------- Syntax: pragma Unreferenced (local_Name {, local_Name}); This pragma signals that the entities whose names are listed are deliberately not referenced. This suppresses warnings about the entities being unreferenced, and in addition a warning will be generated if one of these entities is in fact referenced. This is particularly useful for clearly signaling that a particular parameter is not referenced in some particular subprogram implementation and that this is deliberate. It can also be useful in the case of objects declared only for their initialization or finalization side effects. If `local_Name' identifies more than one matching homonym in the current scope, then the entity most recently declared is the one to which the pragma applies. The left hand side of an assignment does not count as a reference for the purpose of this pragma. Thus it is fine to assign to an entity for which pragma Unreferenced is given. -------------- The last paragraph (allowing assignment) did not appear in the GNAT 3.15p reference manual. The latest ACT pre-release is GNAT 5.00a; it has the same text as 3.16a > I'm sure ACT had good reason for making it so, but it seems to run counter > to 'the principle of least surprises'. I agree. I can only assume that some customer needed the "allow assignment" case, and ACT felt is was a reasonable thing to do, so they added it in GNAT 3.16a. Now that I know it is there, I will probably use it as well, for example for ignoring irrelevant results from Win32 API functions. > I've got another proposal that adds rules to allow with_clause > checking, if it is felt that would be of benefit. I'm still not > convinced about the need to cover > variables/constants/subprograms/entries, but if someone wants to > write up those rules, feel free! I think I can see why Robert Dewar says it's not worth trying to standardize this. In some ways, it is highly specific to the warnings that GNAT gives. If other compilers don't give similar warnings, this pragma is useless to them. I suppose an annex on recommended warnings might be a way to go, but I doubt it is worth it. Perhaps this is a good candidate for a "secondary standard", rather than trying to put it in the main Ada standard. **************************************************************** From: Martin Dowie Sent: Wednesday, April 23, 2003 2:29 AM > I think I can see why Robert Dewar says it's not worth trying to > standardize this. In some ways, it is highly specific to the warnings > that GNAT gives. If other compilers don't give similar warnings, this > pragma is useless to them. I can see why it's not worth trying to standardize the current GNAT pragma (including name) but I think a simpler semantics and differently named pragma is worth the effort. From what Tucker has said this would be an easy change for compiler writers and the simply semantics doesn't have the problem for Janus that Randy described. As for other compilers that don't currently give a warning, the mean implementation would provide them an ideal chance to include a fairly useful warning! :-) ****************************************************************